Most AI side projects die before they see a single user. That's not an exaggeration—it's a pattern I've watched play out in hackathons, Discord servers, and my own GitHub history. The pattern is almost always the same: huge ambition, a week of furious coding, then a silent death when the developer realizes the model they wanted to fine-tune costs $4,000 in compute and the API they planned to build around has a rate limit of 10 requests per minute.
I'm not immune to this. I've started and abandoned more AI projects than I can count. But in the last two months, I shipped three actual MVPs—all with real users, all with real (if modest) revenue. Not because I got smarter or more disciplined, but because I made a set of deliberate choices about scope, infrastructure, and what "done" actually means.
Here's what I learned.
The First Ship: A Lesson in Scope
My first MVP was an auto-tagger for RSS articles. I subscribe to about 80 newsletters and feeds, and I wanted to bucket them into topics without doing it by hand. Simple idea. The problem was that I originally planned to use a local LLM via Ollama, host it on a spare GPU I had lying around, and build a whole pipeline with a message queue.
The first version took me four days to build and never worked reliably. The GPU was too slow, the model kept drifting, and the whole thing felt like maintaining a server farm instead of shipping a feature.
So I deleted 90% of it.
The version that shipped is one Python file. It fetches articles from a few RSS feeds, sends them to an API, and writes the response to a SQLite database. That's it. No queue. No Docker. No GPU.
import feedparser
import requests
import sqlite3
def tag_article(text):
prompt = f"Assign 1-3 topic tags to: {text}.\nRespond with comma-separated tags."
resp = requests.post(
"https://api.example.com/v1/chat/completions",
json={"model": "gpt-4o-mini", "messages": [{
"role": "user", "content": prompt
}]},
headers={"Authorization": "Bearer YOUR_KEY"},
timeout=30
)
return [t.strip() for t in resp.json()["choices"][0]["message"]["content"].split(",")]
for entry in feedparser.parse("https://news.ycombinator.com/rss").entries:
print(entry.title, "->", tag_article(entry.title))
That's the whole thing. It runs every morning via cron. The "database" is a 2KB SQLite file. It works.
The lesson here was brutal but necessary: Nobody cares about your infrastructure choices. They care about what the thing does. I spent 4 days fighting with Ollama and GPU memory. The shipped version took 2 hours to write and costs about $0.03 per run.
The Second Ship: When Feedback is Brutal
Project two was a meeting summary bot for my team. We have three standups a week, and I wanted to automatically extract decisions and action items from the text.
This one actually got users before it was complete. Two teammates started using it after I demoed a rough version. That was exciting until they sent me the feedback.
"Where are the action items?" asked one.
"The summary is fine but it misses the context we discussed," said the other.
I was disappointed. I had built something with actual AI—surely that was enough? But the lesson here is that AI doesn't cover for poor product thinking. The bot was hallucinating decisions that never happened and missing real ones because I hadn't told it what an "action item" looked like in the context of our meetings.
The fix wasn't smarter AI. It was a better prompt and a schema.
def summarize_minutes(transcript):
system = """
You are a meeting assistant. From the transcript, extract:
- decisions: list of WHAT was decided, WHO made it, WHEN.
- actions: list of WHO does WHAT by WHEN.
- blockers: list of any stated problems.
If something is unclear, do NOT guess. Say "UNKNOWN".
Return strict JSON.
"""
resp = call_api(transcript, system)
return json.loads(resp)
That one change reduced hallucinations by maybe 60%. The bot still occasionally invents things, but now it's clearly labeled as "UNKNOWN" instead of fake certainty.
Also: I removed the "summarize everything" feature. Turns out nobody wants a general summary—they want specific extraction. That's the difference between a toy and a tool.
The Third Ship: Cost Reality
For project three, I wanted to build a web scraper that turns product pages into structured data. The idea: give it a URL, get back a JSON object with name, price, and description.
This is where I finally hit the infrastructure wall. Running this against dozens of sites with a general-purpose LLM was going to be expensive. I was looking at about $0.10 per page, which means 1000 pages = $100. That's not sustainable unless someone pays for it.
I considered self-hosting again. I looked at vLLM, TGI, and other inference servers. The setup time alone was 3 days, plus GPU costs (around $0.40/hour on a decent instance). For 1000 pages, I'd need maybe 20 hours of compute, which is $8 of GPU time. That's cheaper than API calls.
Until I account for my own time. Self-hosting requires maintenance, monitoring, and dealing with occasional model issues. That's easily 10 hours a month. At my dev rate, that's $800/month just to keep it alive.
The API path costs $100 for the actual usage, and zero maintenance. I chose the API.
The Reality Check
Here's the uncomfortable truth I've come to accept: "Building with AI" is 10% model choice, 90% product plumbing. The models are commoditized at this point—everyone has access to the same weights. What matters is:
- How quickly you can integrate
- How cheaply you can run
- How reliable the output is
- How fast you can fail and retry
I could have spent another month making the scraper fully autonomous and self-hosted. Instead, I shipped it in 5 days by using an existing API and wrapping it with good prompts and validation logic.
The scraper now runs about 500 pages a day for a couple of small clients. It's not a unicorn, but it exists, it works, and it makes money.
Picking Your Infrastructure Honestly
This is the part that took me the longest to learn: building with AI means choosing your vendor as deliberately as you choose your features.
I've tried running models myself. I've tried the giant cloud platforms. What I've ended up with is a pragmatic, pay-as-you-go approach. For my side projects, I use an aggregator API subscription through a service called tai.shadie-oneapi.com — it's something a friend introduced me to. You get access to multiple model providers (I use it for GPT-4o-mini and Claude Haiku) with a single key, and the payment model is just "pay for what you burn."
That's the sweet spot for side projects. You don't need enterprise contracts; you need predictable, low-cost access to models that you can swap out when pricing shifts.
Is it perfect? No—sometimes I wonder if I'm overpaying compared to direct provider APIs. But it costs me about $15 a month for all three MVPs combined. When I tried assembling my own setup, I spent more in my weekend hours than a full year of this subscription would cost.
What I'd Do Differently
If I could go back two months, I'd change exactly one thing: I'd start each project with a hard budget in mind, both in dollars and in developer hours.
Money budget: Each MVP had a $50 one-time build cost and a $10/month running cost cap. That forced me into API-first, simple-infrastructure solutions immediately.
Time budget: Each project got two weekends max. If it wasn't demonstrably working by day 4, I cut a feature or changed the scope.
I also stopped treating AI infrastructure as part of the project. It's a utility, like electricity or internet. You don't build your own power plant for a side project—you plug into the grid.
The Real Measure
The metric that matters isn't lines of code or model accuracy. It's the answer to one question: Did anything ship?
I shipped three things. They're small, they're imperfect, and one of them sometimes hallucinates action items. But they exist. They do a job. And a handful of people use them every week.
That's more than what most AI projects achieve. Not because I'm smarter or more disciplined, but because I stopped treating this as cutting-edge research and started treating it as software development with a slightly different toolkit.
If you've got an idea that's been sitting in your head for a while, here's my advice: give it two weekends. Wire it up to an existing model API. Make the smallest version that could possibly do the job. Ship it before you're proud of it.
You can always make it shinier later. But you can't fix a project that never saw the light of day.
Top comments (0)