My Adventures in Vibe Coding Tools — The Pain of Versioning (Part 1)
I’m a tech person—not the type who grinds out code all day, but not the type who never touches it either. For me, coding is pure interest; I’m not looking to make a full living out of it, just looking to find some joy in the process of exploration. As my handle suggests, my writing style will be a "raw log"—because I believe the exploration of technology is always a journey. If anyone cares about the process, a slightly refined "exploration log" is often more valuable than a polished summary.
How I Started "Vibe Coding"
My journey into Vibe Coding started with an interview two months ago—or rather, not the preparation for it, but the post-interview reflection. It was a live test where I was told in advance I’d have one hour to build an Agent. I mistakenly assumed it would be a low-code task (since it was a Solutions Architect role), so I spent a day brushing up on Coze. When the interview started and they said it was a "full-code" test, I was totally blindsided. Since I was already there, I tried to wing it using my old code snippets and ChatGPT/Gemini to force out a LangGraph.js implementation. The problem? I hadn't touched it in a month, and LangGraph.js had jumped from v0.3 to v1.0. Other dependencies had changed too, and most of my snippets were broken.
In a desperate "just make it work" attempt, I started compromising. I ditched the PDF parsing (dependency issues), gave up on running the Graph with State (I was in such a rush I missed a parameter and couldn't debug it), and just used LangChain.js with basic context (which forced me to add an intent classifier at the start). By the time I managed to paste the PDF text in manually and get the intent branches working, my hour was up—and I hadn't even written the core logic yet.
The interviewer told me that with my approach, unless I had the questions in advance, it was almost impossible to finish in an hour. But, if I had used something like Cursor with a proper setup, an hour is usually plenty.
That moment felt exactly like 2015, seeing how smooth the iPhone was for the first time. Suddenly, the Nokia in my hand just wasn't "it" anymore.
What Tools Do I Use for Vibe Coding?
Looking at the landscape today, Vibe Coding tools are everywhere, from IDEs to CLIs. I checked out some CLI tools and tried the Gemini CLI, but it felt a bit too "high-end" for my needs. I think the key point is: when the pros are Vibe Coding, they are mostly designing and reviewing code. For me, besides building a POC, I still need to learn. Features like "Jump to Definition" and seeing code diffs in an IDE are essential for me, so I decided to stick with an IDE.
On the other hand, to be honest, I tried Cursor four or five months ago. But as a JetBrains Toolbox user of over 10 years, I just couldn't deal with the UI (even with VS Code, I only use it for config files or as a temporary clipboard). Plus, I have this obsession with always having the root directory file tree expanded in the top left. The first time I opened Cursor and saw that empty, "where-do-I-even-start" interface, I gave up in less than an hour. When I reinstalled it two months ago, the new version felt much cleaner and at least acceptable, so I won't nag about that anymore.
I tried building some POCs with Cursor. As a free user, it was great until the credits ran out. The "stamina" wasn't quite there. Back then, I tried switching to Gemini 2.5 Flash—it’s much cheaper and almost impossible to run out of credits, but the performance definitely took a hit.
I also tried Google's Firebase Studio. It’s a web-based IDE with a VS Code-style interface. The "everything-in-browser" approach is fresh, but considering the usual "connectivity issues" with Google products here, even with tools, the experience was a bit flaky and prone to disconnects.
Lately, I've been experimenting with JetBrains + Google Code Assist. Even though Code Assist is just a plugin, it has Vibe Coding capabilities. However, since JetBrains isn't as "open" as others, there are many functional limitations. For instance, you can't just click to run a script; you have to manually copy the command it gives you into the terminal. Support for peripheral tools is almost non-existent. I started with WebStorm 2025.1.1 (released mid-2025), which only supported Prompt Templates and MCP. And the MCP didn't even support HTTP requests; I found all sorts of issues during stdio testing. You couldn't even pick the model—it seemed to be locked to Gemini 2.5.
Since MCP was acting up, I tried upgrading WebStorm to the latest 2025.3.1. Then, a "miracle" happened: my Gemini connection died. After researching with AI for a while, I concluded that the 2025.3 major release had a massive change—JavaScript now has its own Runtime. As a result, my previous global proxies or environment variables stopped working. I couldn't find a fix with my current proxy setup, and the AI suggested moving to a TUN-mode proxy, so I put that aside for a bit.
I looked at other candidates and spent an hour on the Gemini CLI before giving up again. I went back to Cursor, but my quota vanished instantly. Finally, I saw Google's new Antigravity. This IDE looks very ambitious. I wanted to try it, but got stuck at the login screen. A quick search revealed—you guessed it—the same proxy issues. At that point, I realized I really had to spend some time figuring out this TUN thing. So, I spent the next day on that.
Today, once I got the TUN setup working, I finally logged into Antigravity and could actually start experimenting.
Now, let's get back to our main topic: the nightmare of versioning.
How Painful is Versioning in Vibe Coding?
If the libraries you use were designed with forward compatibility in mind, and the ecosystem maintained perfect dependency harmony, you might never feel this pain.
While I was messing with Google Code Assist over the past few days, a core theme emerged. I wanted to untie the knot I encountered during that interview: modern software libraries move too fast. Many updates happen after the training cutoff for LLMs. New changes are often incompatible with old ones, meaning the AI gives you old code that breaks when you install the latest version. But if you don't use latest, the AI often suggests random versions and gives you code that simply won't run.
Here are a few glaring examples:
OpenAI API Model Calls in LangChain.js
Letting an AI write LangChain/LangGraph code is a giant trap. From what I’ve seen in LangChain.js and LangGraph.js, the syntax changes between v0.1, v0.2, v0.3, and v1.0 are massive. AI models often fail to match the correct version in their answers, leading to parameter errors or deprecated syntax.
For example, in LangChain.js v0.3, calling an OpenAI-compatible model (like Doubao API) like this was fine:
const model = new ChatOpenAI({
apiKey: process.env.OPENAI_API_KEY,
configuration: {
baseURL: process.env.OPENAI_BASE_URL,
},
model: "doubao-seed-1-6-flash-250828",
temperature: 0.7,
});
But in v1.0, this throws an error:
'Incorrect API key provided: ************************. You can find your API key at https://platform.openai.com/account/api-keys.'
You guessed it—v1.0 reserved the model parameter exclusively for OpenAI and uses it as the "flag" to identify a native OpenAI call. Other compatible models must now use the modelName parameter.
I've even seen AI suggest this for the same code:
const model = new ChatOpenAI({
apiKey: process.env.OPENAI_API_KEY,
baseURL: process.env.OPENAI_BASE_URL,
model: "doubao-seed-1-6-flash-250828",
temperature: 0.7,
});
In reality, LangChain.js never had this syntax. The AI likely "hallucinated" this from the LangChain Python version, which uses a base_url parameter in that position.
Kubernetes JavaScript SDK Version Changes
Logic dictates that K8s is a massive project, but maybe not enough people use the K8s + JS/TS combo, which leads to issues.
I ran into this with WebStorm + Google Code Assist. When I asked the AI to generate code for K8s resources, it always gave me something like this:
await coreV1Api.readNamespacedPod("my-pod", "default");
But if you check the signature for readNamespacedPod in the actual library, the first argument is now a params object containing name, namespace, etc. It should be:
await coreV1Api.readNamespacedPod({
name: "my-pod",
namespace: "default"
});
This was a breaking change across the entire SDK. In the current v1.4, all resource calls have shifted to this new format.
Once you fall into this trap during Vibe Coding, it’s a nightmare. You chat about something else, ask it to refactor some code, and it "helpfully" reverts every call in the file back to the old format. You tell it not to, you show it the correct way, but it forgets after a few rounds. Sigh...
What Do I Do Now?
I've been writing for too long today. I'll pick this up again tomorrow.