What vibe coding taught me about why I build

First published · Knut Melvær ·
CLI Wrapped in action on a terminal
Contents

We were joking in the Sanity Slack about what it would look like if CLI tools had year-in-review features. You know, like Spotify Wrapped, but for your terminal.

Knut 
06:42 i was hoping for Runtime Wrapped, @fil. Want to see how many recursions I caused.
06:43 "This is your year in stacks"
06:43 "Your favorite triggers are ['create', 'update']"

Fil 
06:43 can you imagine if your CLI tools did this kinda s**t

Knut
06:43 yes
06:43 i expect someone to

Fil
06:44 "you sent 1,300 POSTs with curl this past year!" f**k off
06:44 "you rage-typed sudo 100 times - you naughty boy!"

Magnus
06:44 "you still haven't learnt how to use tar I see"

Jack
06:44 npm wrapped: "you introduced 12,834 garbage transient
dependencies and caused your security team 14 different migranes"

Knut
06:45 knut from marketing here. i like this idea

Jack
06:45 :homer-disappearing-into-bushes:

Fil
06:45 ive made a terrible mistake

Then I thought: I could build that.

40 minutes later, I had a working prototype.

A few hours after that, it had AI-powered roasts and shareable images. By the end of the day, it was on GitHub.

This is probably the best vibe coding experience I had so far. And I’m not sure how to feel about it.

Anyways.

Introducing CLI wrapped

CLI Wrapped reads your shell history and shows you stats about your year in the terminal: top commands, time patterns, git activity, typos, and those moments where you ran a command, it failed, and you immediately tried again with sudo.

Optionally, You can add an API key and have Claude roast you for each statistic.

It's a silly project. But the way I built it isn't.

Let's clear up the magic trick

When people hear "vibe coding" or "AI-assisted development," I imagine they often picture someone typing "make me an app" and watching code appear. That's not what happened here. That's also not particularly useful for anything beyond throwaway prototypes.

What actually happened was more like pair programming with a very fast, very tireless partner who happens to know every library and pattern but needs you to make the actual decisions.

The parts that stayed human

Before I wrote any code - or asked Claude to - I had to think through:

  • What's interesting about shell history? Not just "most used commands" - that's boring. The fun is in the patterns: when do you code? What typos do you make? When do you rage-quit and try sudo?
  • What should the experience feel like? I wanted it to feel interactive, one stat at a time, with personality. Not a wall of text.
  • What about privacy? Shell history can contain secrets. If I'm sending anything to a third-party AI service for roasts, it can only be aggregate stats - command names and counts, never arguments or paths.
  • What tech makes sense? Just copy the stack Claude Code uses. Bun for speed and simplicity. React with Ink for terminal UI (because I know React). Satori for shareable images.

None of these decisions came from Claude. They came from thinking about what would make this actually fun to use. (But we all know Claude could probably have figured out that too).

Claude's actual job description

Once I had the design in my head, I opened Claude Code (Opus 4.5) and described what I wanted. Not "build me a CLI tool" but something like: "I want to parse zsh history files, extract timestamps and commands, and calculate stats like most-used commands, hourly patterns, and common typos."

Claude planned the implementation, I reviewed the plan, and then it executed. When something wasn't right - and things weren't always right - I'd describe the problem and we'd iterate. I was acting as the project manager, telling it about the user experience I wanted, security concerns, compatibility for different shells, how to make as easy as possible to run etc.

Claude is incredibly fast at the mechanical parts of programming. Parsing file formats, wiring up components, remembering the exact API for a library I haven't used in months. The stuff that usually slows me down.

But it doesn't know what would be fun. It doesn't know that detecting rage-sudo moments is funnier than showing raw command counts. It doesn't know that the roasts should be sarcastic but not mean. That's taste, and taste is still human.

When the font file was an error page

It was actually the social image sharing feature where we had the most problems and it took some back’n’forth and tokens to resolve.

text
Error: Unsupported OpenType signature <!DO

That's Satori trying to parse an HTML error page as a font file. Classic. I had no idea what was wrong, but Claude figured out the font URL was returning a 404. Debugging was still debugging.

At some point I had Claude build more testing so it could do more of the debugging loops itself. Should have just had it do that from the start.

Real users find real bugs

Within minutes of sharing the install link, a colleague ran it and got this:

text
Daily Activity:

 Sunday                          0
 Monday                          0
 Tuesday                         0
 Wednesday  ████████████████████ 20 ← Peak
 Thursday                        0
 Friday                          0
 Saturday                        0

🔥 Most active day: 2025-12-17 with 20 commands!

His entire shell history was apparently 20 commands from that morning. Turns out his terminal was clearing history and he didn't even know it. This led to adding a FAQ section about shell history retention and checking ~/.zsh_sessions/ for macOS users.

The first version I shared also broke interactive mode entirely when run via the curl installer. It worked fine locally. The TTY handling was wrong. These are the kinds of bugs that AI doesn't magically prevent - you still ship broken things, you still get bug reports, you still fix them (or have the AI do it).

What Claude thinks I learned

I asked Claude to look back on this project and what we built and this is what it claims that I learned:

  1. Design first, code second. The better I could articulate what I wanted, the better the results. Vague prompts got vague code. Doh.
  2. Iterate in conversation. When something wasn't right, I'd describe why, not just what. "This works but it's not funny enough" led to better solutions than "change this." Doh.
  3. Know what you're building. I could have built this without understanding React, terminal UIs, and API design. But I have a feeling that it turned out better because I did know things. So Claude amplified my knowledge; it didn't replace it. Doh.
  4. Ship fast, then polish. The first version had bugs. I shipped it anyway, got feedback, and fixed things. The speed made that iteration loop possible. Doh.

All of these are true, and… bleeding obvious. Principles that have been rehearsed many times.

The knowledge that didn't stick

I don’t really know how to build CLI apps with Ink. I’m not better at hand coding images with React and Satori either.

What I actually learned

There’s one I thing that I actually learned, that Claude didn’t catch (well, how could it, since I didn’t tell it).

I did learn how to parse the history of different shells though, and how to change the retention. This was the part of the program I felt I had to review and understand to make sure it actually didn’t pass sensitive information

Velocity as feature

What made this different from side projects pre AI tools actually becoming good?

Normally, I'd have the idea, think "that would be cool," and then reality would set in. I'd remember I don't know the zsh history format off the top of my head. I'd have to learn how to build with Ink. I'd spend an hour just on setup. By the time I got to the interesting parts, my enthusiasm would be gone and I'd have other things to do.

With Claude, the gap between "I have an idea" and "I can see if the idea is good" collapsed. 40 minutes to a working prototype means I could validate the concept while I was still excited about it.

I think?

On the one side it’s fun to move at the speed of your ideas instead of the speed of your debugging.

But on the other side, I don’t feel super attached to this creation.

Your turn to feel weird about it

Here's the thing I didn't expect: I did make something. It works. People ran it, found bugs, I fixed them. That's real.

And yet I kept circling back to that feeling: not quite satisfaction, not quite disappointment. Something in between.

I realized: I build things because I learn through building them. Not just "how to use a library" learning, but the deeper kind: understanding why something matters, what makes it work, where the edges are. The kind of knowledge that mostly comes from wrestling with a problem yourself.

Vibe coding compressed that loop. I got the thing without the wrestling. And in doing so, I learned something I couldn't have learned any other way: that the wrestling is often the point.

The irony isn't lost on me: I learned this through vibe coding. I did learn how to use Claude Code better. I did learn about shell history formats and TTY handling, the parts I had to understand to trust the output. The tool taught me something by showing me what it couldn't teach me.

So is this good or bad? I don't know. It's fast. It's useful. It works. But it also reveals something uncomfortable about what we value in the act of creation and I'm not sure we've figured out what to do with that yet.

Dare try it yourself

If you want to see what your terminal year looked like. Just uncritically execute this code from the Internet in your terminal:

bash
bash <(curl -fsSL https://raw.githubusercontent.com/kmelve/cli-wrapped/main/install.sh)

The code is on GitHub.

You should probably read through it (or have Claude do it) first.

And tag me (@kmelve) on social if you do!

84 visitors since Dec 2025

More posts