
How we build single purpose apps with AI
We build small tools. One tool, one job. Here's how we do it — and what we learned along the way.
Start with the expectations
Managers want AI. Yesterday.
In their heads, AI means 10x speed. Maybe more. So you either ship fast or explain why you didn't. Neither option is fun.
We decided to ship fast. This allows quick iteration. Because when managers can "touch" the app, they can provide quick feedback.
Browse our data apps and you'll see examples of what that looks like in practice. Each tool solves exactly one problem, one reason to exist. Think of them as functions with a face — a GUI wrapped around a Python call or SQL query.
They all share one thing: we built them with AI help.
We don't have a favorite model
ChatGPT, Claude, Gemini, Qwen, DeepSeek, Grok. We've tried them all.
We're not loyal. We're experimenters.
No model wins every time. Each has blind spots. Each surprises you differently.
Here's the honest version: most models get you 80-85% of the way there. Then something breaks. You ask for a fix. It fixes that thing — and quietly breaks something else.
It is especially true for newer tools, like marimo, that have limited training data. There aren't many Stack Overflow threads about it yet. LLMs can only work with what they've seen. For HTML and vanilla JavaScript though? Models shine. Plenty of examples. Thousands of Stack Overflow answers.
For AI, the tech matters.
Three types of apps we build
1. Marimo notebooks turned into apps
Marimo works like Jupyter. Develop in a notebook, test there too. When it's ready, upload one file and run it as an app. Marimo's built-in UI elements handle most of the notebook-to-app transition. It's clean.
First app load is slower though — marimo spins up the Python runtime on demand, so users wait a few extra seconds that a FastAPI app or plain HTML page never makes them wait.
2. FastAPI backend + HTML/JS frontend
FastAPI starts fast. Low overhead.
The frontend is a single HTML file. No frameworks. CSS and JavaScript live inside that one file. No external fonts. No CDN calls. Everything ships in one request.
Why no React or Vue? We thought about it. Then decided it was unnecessary complexity for what we needed. Modern browsers handle a lot. The final code stays small. Users don't wait.
3. Pure client-side HTML/JS
No backend at all. The whole app runs in the browser.
For the right use cases, this is the fastest possible option. Nothing to deploy server-side. Nothing to break.
What we actually care about
Our priorities, in order:
- Fast development cycles
- Fast loading
- Low resource usage — CPU-only containers (where possible), limited RAM
- Easy production deployment
- Honest testing of whether current AI can actually help
That last point matters. We're not just using AI to seem modern. We're testing what it can and can't do.
This isn't vibe coding
Vibe coding is prompting until something works, then shipping it.
We don't do that.
AI replaces search engines and developer forums for us. It drafts. It suggests. It gets us unstuck fast.
But it doesn't replace the person who understands the code. Not today. Maybe not for a while.
Deployment alone makes this clear. If you can't configure a backend, you're dependent on someone else's platform forever. The AI can write the code. It won't set up your infrastructure.
Not everything needs AI
This is worth saying plainly.
Take PDFs as a good example. Everyone reaches for an LLM to parse them. Often that's the wrong move.
The MarkItDown Python library reads machine-produced PDFs without any AI. Faster. Cheaper. More predictable.
It won't do OCR. Scanned documents need a different tool. But for PDFs generated by software? The library handles it fine.
Same goes for image resizing. No model needed.
Match the tool to the problem. Don't over-engineer.
What we haven't figured out yet
AI makes mistakes. Whatever ships to production needs review from someone who can read the code.
That's the part vibe coding skips. It's also the part that bites you later.
Our apps are mostly thin GUIs over Python libraries and LLM calls. The hard part isn't the code. It's knowing what the code should actually do — and whether it's doing it.
You might also be interested in
Blog

2025 in review

How we use AI for marketing

The case for small language models
Data Apps

Speech to Text

EU Funding and Tenders

