Skip to content

Navid's Blog

Ideas, Experiments, and Lessons Learned

Menu
Menu
Dark photo of code on a laptop screen

I Vibe-Coded a Tool in One Afternoon — It Died on Its First Real User

Posted on September 6, 2026September 6, 2026 by Navid

The Scene

Forty minutes to build. Two days to clean up. I’d make the first trade again, honestly. It’s the second one I’d like back.

Our support team wanted a tiny internal tool: pick a date range, get a CSV of billing rows. The kind of request I’d normally park in the backlog for a sprint, except I was deep in a vibe coding phase that month (I wrote about the whole experiment earlier) and figured this was a perfect low-stakes target.

My entire prompt was one sentence. “Small internal web tool that takes a date range and returns a CSV of billing rows.” No file sizes, no mention of where it would run, no mention of what else lived on that box. Keep that last part in mind. It worked great on my test file, all twelve rows of it, and I pushed it to the internal server the same afternoon. Felt like cheating.

The Spiral

Monday, 10:40 AM, the internal box starts swapping. Then the metrics sidecar on the same host (yes, same host, I know) stops reporting and one of our dashboards goes blank. Pager fires. I assumed something boring: disk full, nightly job, bad deploy. All three checked out fine, which just annoyed me more.

Nothing in the logs pointed at my little tool. Something was quietly eating the box’s 4GB of RAM. I restarted the sidecar twice before it occurred to me to look at what else was running there.

There it was. A python process holding 3.8GB, attached to a Flask route I recognized.

The Discovery

The whole incident came down to one line: pd.read_csv(path). The agent read the entire file into memory, which is a completely reasonable thing to write when nobody has told you that real exports run 2 to 4GB. The demo file had twelve rows. The question never came up, so the code never handled it.

To be fair, the agent didn’t do anything wrong, exactly. It built what I described. Looking at code that was technically correct and completely unsuited for the real world it had just met, that was the uncomfortable part.

The Lesson

  • The model writes what you said, not what you meant. I gave it zero information about scale, so it made zero assumptions about scale.
  • Chunking is a default, not an optimization. read_csv(..., chunksize=50_000) was one argument away the entire time.
  • Shared hosts need memory budgets. My tool misbehaving was almost beside the point; the innocent sidecar that died alongside it is what actually paged me.

What I’d Do Different

  1. Say the ugly numbers in the first prompt. Biggest file, worst case, row counts. The agent can’t read minds.
  2. Demo with production-shaped data. Twelve rows is a toy and deep down I knew it.
  3. Give anything user-facing its own container. One process, one blast radius, no innocent bystanders.

External Resources

  • pandas docs on scaling to large datasets
  • psutil, for watching a box eat its own RAM in real time
  • Real Python on Python memory management

The exporter runs fine now. Chunked, isolated, and still used by support every day, which I admit surprised me. So yeah: forty minutes of vibe coding, two days of paying for it, and the fix was one argument I could’ve typed in the original prompt. I’ve had worse trades, but not many.

Categories

  • AI Experiments
  • Coding
  • Debugging Stories
  • Hot Takes
  • Ideas
  • Lessons Learned
  • Productivity
  • Project Management
  • Systems & Architecture
  • Uncategorized
  • Vibe Coding

Recent Posts

  • 5 ORM Mistakes That Pushed Me Back to Raw SQL
  • Norway Vanished From Our App for Two Days — It Was One Unquoted Line
  • I Ignored a Deprecation Warning for 11 Months — It Worked Until It Didn’t
  • Why I Stopped Time-Blocking (And What I Do Instead)
  • I Vibe-Coded a Tool in One Afternoon — It Died on Its First Real User