โ† Blog ยท August 21, 2026

Vibe coding needs a safety net

Generating a whole application from a short description is impressive, but the parts you can't see are the parts that decide whether it can be used for real work. In this post we'll look at what should be generated, and what should already be there.

The Snill mascot bouncing safely in a net strung between two posts, with a small app window tumbling down towards it
Generating the app is the easy part. What matters is what it lands on.
TL;DR

Vibe coding has made it remarkably easy to get something running. With ChatGPT, Codex, Claude Code or any of the similar tools, you describe an app in a couple of sentences, and less than a minute later there is a page in the browser with buttons, a table and a form that submits. It looks like an application, and as a demo it's good enough.

The trouble starts when you send the link to a colleague.

In the simplest case, the one where you asked a chat tool for an app and it gave you one, there's no login, so anyone with the URL is an administrator. The data is kept in memory, so a refresh wipes it. If two people edit the same record at the same time, the last click wins. Nobody can see who approved what, or when, or whether the number in the report is the number that was actually approved.

This is the gap that stops most internal tools from ever being used in practice. It's rarely the idea, the user interface or the business logic that fails. It's everything underneath them.

What an internal app actually needs

Before a single real person can use an internal app, quite a lot has to be in place:

Generative AI is very good at the part you can see, and the results really are impressive. It's less reliable at the part you can't, and when it gets that part wrong, nothing looks broken. The page still renders. The bug goes to production behind a perfectly nice user interface. So the real question isn't whether AI can write code, because it clearly can. It's whether you can tell if the code it wrote is safe to put your suppliers, your employees or your incident reports into.

The better tools have already closed part of the gap

It would be unfair to leave it there, because the tools have moved, and there are two families worth separating.

The first is the coding agents: Claude Code, Codex, Cursor. They write a real codebase, and they're very good at it. If you ask for authentication and a Postgres database and a permissions layer, you will get all three, and they will probably work.

The second is the app builders: Lovable, Bolt, Replit and others in that direction. They go further and hand you a database, a login screen and somewhere to run it, without you having to think about any of it. For plenty of jobs that really is enough, and we'd rather people used them than kept the process in a spreadsheet.

So the problem is no longer that these tools can't produce a working app with a database behind it. They can. The problem is what you are holding afterwards.

What you are holding is a codebase, or an app inside somebody's builder account, and it belongs to whoever made it. That raises a set of questions that have nothing to do with how good the generation was:

That's the honest version of the problem, and it's the one we hear most often. The hard part isn't building the prototype. It's getting from an AI prototype to a system the organization can operate without depending on one person or one laptop.

Two ways to close the gap

The first way is to treat vibe coding as a prototyping tool, and then hand the prototype to developers to rebuild properly. That works, and plenty of teams do it. It's also slow and expensive, and it means the person who understood the process (the operator, the controller, the quality lead) has to hand that understanding to somebody else and hope it survives translation.

The second way is to change what is being generated.

Instead of asking a model to invent an entire application from scratch every time, you give it a runtime that already contains the difficult parts, proven and identical for every app built on it, and it behaves the same way on Tuesday as it did on Monday. What gets generated is only your part: the data model, the screens, the workflow and the rules.

That's the safety net. It isn't a guardrail that stops you doing things, it's a floor that stops you falling.

What is fixed and what is generated

This is the split we built snill.ai around (the generation itself currently runs on Claude, on infrastructure in the EU).

The Snill mascot standing on a solid stone slab, with three app windows floating above it, one of them still drawn as a dashed outline
The slab is the same for every app and nobody regenerates it. What sits on top is yours, and it is meant to keep changing.

Fixed, proven and not regenerated for every app:

Generated from your description:

You describe the business and the platform supplies the engineering. If the generated part turns out to be wrong, you change it in plain language and try again, because the mistake is confined to the layer where it's safe to make one. A badly named field takes five seconds to correct, whereas a badly designed permission model is the kind of thing you end up writing an incident report about.

The AI proposes, you approve

There's a second half to this, and it's the part we get asked about most once people have understood the first. Keeping the platform fixed protects the layer underneath, but the generated layer still has to change over time as the business changes. An AI that can rewrite your data model whenever it likes isn't much of an improvement on an AI that got it wrong the first time.

So we constrain what the AI is allowed to do. It can propose changes, but it can't commit them.

When you ask for a change in Develop mode, nothing happens to the app straight away. The proposal is drawn into the model grid as a color-coded diff (green for added, amber for changed, red for removed) and it sits there until you click Apply.

The same applies to the data, and that's where the assistant earns its keep. It knows your model, so you can ask it things that cross collections - which invoices are unpaid this month, what the total revenue by customer was last quarter - and get an answer rather than a filter you have to build. Ask for a report and it writes one, with summary, tables and charts you can export to PDF, CSV or JSON. Ask it to change something and it proposes the change for you to confirm. Scan to fill behaves the same way: it reads a receipt or an incident photo, drafts the fields, and waits. Nothing is saved on its own.

Worth saying plainly, because the tools in the previous section don't give you this at all. With a coding agent or an app builder the AI is there while the app is built, and gone once it runs. What ships is the app. Nobody in finance can ask it which suppliers went over budget last quarter, because there's nothing there to ask. Here the assistant is part of the platform rather than part of the build, so it's still there on day 400, for every app.

Every change that is applied becomes a new version, and the version history records whether it was made by the AI or by a person, so you can look at what changed and roll back to any earlier version.

It's a small mechanism with a large consequence. A person sees every structural change before it takes effect, and can undo it afterwards. The AI does the work of translating a sentence into a schema change, which is the tedious part, but it doesn't get to decide.

Consistency across your internal apps

One consequence of the fixed layer only becomes obvious once you have more than one app. If every internal tool is generated separately, every internal tool is different. The expense app has its own login, its own idea of what a user is, and its own way of exporting a list. The deviation app has another. Somebody joining the company gets access to five tools and has to learn five interfaces, none of which quite work the way the others do. Somebody leaving has to be removed from five places, and it only takes forgetting one.

When the platform layer is fixed, that doesn't happen. Every app has the same navigation, the same behaviour in lists and forms, the same search, the same export and the same way of setting up roles. The second app takes almost no time to learn, because it's the first app with different fields in it. Members belong to the organization rather than to an app, so people are invited once and removing somebody is one action rather than five. The REST API is generated the same way every time, so integrating the fourth app is the same job as integrating the second.

Consistency of this kind isn't exciting and nobody asks for it in the first conversation. It's what makes it reasonable, though, to run fifteen small internal apps instead of three big ones and a lot of spreadsheets.

What this is for, and what it isn't

The constraint that makes this work is also what makes it wrong for some jobs, so it's worth being specific. Snill isn't a vibe coding tool with better plumbing, and we're not trying to build a general app builder. The apps it generates have a shape: something gets captured, it's related to other things, it moves through a few states, somebody approves it, and it gets reported on. If you sketched your process on a whiteboard and it came out as boxes with arrows between them, it's probably the right shape.

That doesn't mean there's no logic in these apps. Calculations, validation rules, state transitions and notifications are all part of it, and you describe them the same way you describe everything else: the amount is hours times rate, a receipt is required over 10,000, email the owner 30 days before the contract ends. But the logic is declarative. It's expressed as calculated fields, rules and triggers that the platform runs, not as code inside the app.

So if the value of your app is in the data and the process around it, this fits.

There's a middle case that most real apps reach eventually, where you need one piece of genuine code: charge the card when an invoice is marked as sent, generate a document, fan out to three other systems. Snill's automation stops at the declarative line on purpose. What it does instead is emit the event as a signed webhook and let something else run the code, whether that's what you already use or Codehooks, which the same team built for this job and which writes its result back through the app's REST API (there's a full walkthrough of that pairing). The system of record stays clean, and the custom logic sits outside it where it can be tested and deployed like any other code.

What doesn't fit is an app whose value is the behaviour itself: a pricing algorithm at the center of the product, a real-time collaborative canvas, a bespoke interface, a public product with its own design language. There the constraint stops being a safety net and starts being a ceiling. Use Lovable, use Bolt, use Claude Code and own the codebase. That's a real answer, and for those jobs it's the better one.

What's left after you draw that line isn't a small category. It's the large and fairly unglamorous set of tools that companies actually run on: expense approvals, helpdesk and ticketing, a small CRM for a team of nine, onboarding checklists, deviation and incident reporting, supplier registers, equipment tracking, site inspections, and the audit preparation spreadsheet that four people edit and nobody quite trusts.

These applications have a shape that fits the approach unusually well:

That last point is the one that tends to get underestimated. Internal doesn't mean unimportant. An internal tool holds employee data, supplier terms, customer contacts and quality records, and in a regulated industry it holds things that an auditor will eventually ask about. "It's only an internal app" has never worked as a defense.

Buy, build, or somewhere in between

Most organizations make the same trade today, usually without thinking about it. When you need a tool for a process, there are four options:

  1. Buy SaaS. You get robust engineering and roughly 60% fit. The remaining 40% turns into workarounds, a shadow spreadsheet, and a monthly bill for features nobody opens.
  2. Use a spreadsheet. You get 100% fit and no engineering at all. No permissions, no audit trail, no concurrency, and one person who understands the macros and is currently on holiday.
  3. Use a no-code tool. Airtable, Notion, Glide, Retool and Bubble all live here, and they get you a long way. Airtable is very good at structured data, and a great deal of what companies run on is an Airtable base that quietly turned into real software. They strain further in: permissions per person rather than per role, a workflow that needs enforcing rather than agreeing, an audit trail somebody eventually asks for. Retool and Bubble go deeper but expect a developer, and Retool expects a database to point at.
  4. Build it. You get 100% fit and full engineering, at the price of a development project, a backlog and a place in the queue.

Generating the app on top of a proven platform collapses the last option into something an operator can do in an afternoon. You stop trimming the process to fit the product, and the tool matches how the work is actually done, including the awkward step that everyone in your industry has and no SaaS vendor has ever heard of.

Fit isn't a nice-to-have in internal tooling, it's the reason the tool exists in the first place. A workflow tool that doesn't match your workflow is just another place to type things twice.

An example: deviation reporting

Say you describe a deviation reporting process, an avvik in Norwegian, a word that every quality system in the country is built around and that no international SaaS product ships a table for. You describe it the way you would explain it to a new colleague. Anyone on site can report a deviation with a description, a category, a severity and photos. It goes to the quality lead for that department, who classifies it, assigns a corrective action with a deadline, and closes it when the action is done. Management wants a monthly overview by category and site.

What comes back isn't a mockup. It's an app with a real schema behind it, logins for the people who need them, a quality lead who sees their own department's reports and not the other three, and a history on every record showing who changed the severity.

Then you start using it, discover that severity needs a fourth level and that the deadline should default to fourteen days, and you say so. That's the loop: describe, run, adjust, with the database, the identity and the permissions holding still underneath the whole time.

Summary

Vibe coding didn't fall short because the code generation was bad. It fell short because generating everything means guaranteeing nothing.

Put a proven data model, database and identity layer underneath, narrow the scope to internal productivity apps, and the same technique stops being a party trick. You get the speed of describing what you want, on infrastructure somebody already got right once, for every app, instead of re-inventing it each time you press generate.

Move fast, but do it over a net.

Describe your own process โ†’ - it's free to start, or you can begin from a ready-made template and adjust it by asking.


snill.ai turns a plain-language description of a business process into a working internal system, with the database, users and permissions already in place. Your business is the spec.