Shipping a tiny tool was
harder than building it
I built a small thing in an afternoon and then spent two days trying to get it online. Most of that time had nothing to do with the code. Here is what actually happened, in plain words.
What I built
My college has a portal called VTOP. Attendance, marks, timetable, exam seats, all of it lives there behind a few clicks. I wanted to just ask for that stuff in normal language instead of navigating pages, so I wrote a small program that logs into VTOP and reads those pages for you. It plugs into AI assistants like Claude and Cursor as a tool they can call.
Writing it was the quick part. The slow part was publishing it so anyone at my college could install it with one command. That is the part worth writing about.
It felt like working with a person
I did the whole thing with an AI assistant. The part that stayed with me was not that it wrote code. It was how much it acted like a slightly overconfident colleague.
It would guess why something was broken, fix that guess, ship it, and the bug would still be there. Then it had to stop and admit the guess was wrong and look again. That happened more than once. When the login needed a captcha solved, it showed me the wobbly image and read the letters itself instead of making me type them. When login needed a password it did not have, it did not fall over. It just asked me in the chat, the way a person would.
That is the real difference between a tool and a teammate. A tool stops when it hits something it did not expect. A teammate keeps going and tells you what it is unsure about. Watching it keep going was the interesting part.
What publishing even means
When you install something with a command like npm i something, your computer downloads a small zipped parcel from a public warehouse. That warehouse is npm, basically an app store for code. The parcel is called a tarball.
A tarball is exactly what it sounds like once you ignore the name. It is a folder squashed into one file so it can travel as a single thing, like vacuum sealing a packed bag. Publishing is sealing the bag and mailing it to the warehouse. Installing is someone getting the bag and unpacking it. That is the whole idea.
The catch is that the bag remembers more than the clothes in it. It also remembers a small label on each item. One of those labels is where everything broke.
My computer could not ship it
The tool worked fine on my machine. I published it. People on Mac and Linux could use it. Anyone on Windows got a flat error saying the command was not recognised. It would not even start for them.
The code was fine. The problem was one invisible label on one file inside the bag. The label says whether a file is just data or whether you are allowed to run it as a program.
On Mac and Linux every file carries that little flag. A program needs the run me flag set. My tool was going out without it. So a Windows machine would unpack the bag, try to run the file, and find something that, going by the label, was not a program at all.
That took a while to accept. The reason I could not ship a working tool had nothing to do with the tool. It was a property of the machine I was mailing it from.
The wrong turn
Before we found the real cause we chased a fake one. The tool had a name and the command to run it had a name and they did not quite match. That looked like a believable culprit, so we renamed things, shipped again, and it was still broken.
We had pattern matched. We saw something that looked like a known kind of problem and fixed it without checking it was the problem. The real fix only showed up when we stopped guessing, installed the published parcel ourselves, and looked at the actual label on the actual file. The missing flag was sitting right there.
The most useful thing I did all week was boring. Reproduce the failure exactly, then look at what is really there instead of what I assumed was there. Every hour I lost was an hour spent fixing a theory I never bothered to check.
Letting a clean machine mail it
If my Windows laptop cannot set the run me flag, the answer is to not mail the bag from my laptop. Instead, every time I want to release, a fresh Linux machine starts up in the cloud, builds the tool, sets the flag properly, checks that it starts, and mails it. Then it shuts down.
That is all CI really is. A clean machine that does the release the same careful way every time, so a messy laptop is never part of it. I push a version tag and the machine does the rest.
There was a smaller question hiding here. How does the warehouse know the machine is me and not someone pretending to be me. The old way was a long password you paste into the machine. The newer way, which I used, is more like a trusted handshake. The warehouse and the place the code lives vouch for each other directly, so there is no secret to leak or to forget to renew.
A receipt nobody can fake
The machine also attaches a receipt. It states, publicly and with cryptography, that this exact parcel was built from this exact code by this exact machine. The name for that is provenance. If someone ever took over my account and shipped a poisoned version, they could not produce a matching receipt.
The receipt only works if the code is public too, so I made the repository public. That sounds risky until you remember the built tool was already downloadable by anyone the moment it was published. Open source just lets people check it instead of trusting me. We did scan the whole history first to be sure no password was ever committed. It was clean.
The small human stuff
Once the shipping was solved, the rest of the work was about how it feels to use. When the tool did not have your login saved, an early version replied with a wall of options, a guide to setting environment variables, and a question about which campus you were at. All correct. Completely tiring to read.
The fix was not code. It was tone. We told the assistant to ask one short question, what is your username and password, and stop there. The tool got friendlier without getting any smarter, and that was the right trade.
What I would tell myself before starting
The code is rarely the hard part
Building the thing took an afternoon. Shipping it correctly for everyone took days. Packaging and distribution are real work, not an afterthought.
Reproduce before you theorise
Most of the time was lost fixing confident guesses. The dull loop of reproduce, then look, is what actually closed it.
Take yourself out of the release
Works on my machine is a warning, not a win. A clean automated release removes a whole class of bugs that come from the machine and not the code.
Working with AI is managing a teammate
It is fast and sometimes confidently wrong, same as anyone. The value is not blind trust. It is a partner that keeps pulling the thread while you keep it honest.
The tool was a few hundred lines.
Everything around it was the lesson.
You can try the actual thing, vtop-mcp, or read the code. The bug is fixed. The story was the point.