I have mentioned before how I have continued using Windsurf to build more things, since my success using it with sqlmesh and dlt.
One of the things I developed was an Obsidian1 community plugin that I named LLM Tagger. The idea is straightforward: the plugin could utilise a local LLM to tag the notes in my vault. My vault contains various types of content and accumulates over time with meeting transcripts, ideas, plans, and so on, continually expanding.
Tagging all my documents by hand is theoretically possible but realistically improbable. There are a few key themes that I wish to use to retrieve and connect documents together. The way I envisaged it working was to provide an input box for adding a list of tags, then select a local Ollama LLM from a drop-down menu to use for the tagging that would append tags from the list.
So, I set up a new Windsurf window and chatted with Cascade in write mode. I naively explained what I was doing, and it generated code accordingly. After a couple of hours, primarily spent realising exactly how I wanted this first iteration of the LLM Tagger to function, I had a working prototype.
I tested it on my vault, and this is crucial - I don’t know Typescript, which is the language Windsurf opted to write the plugin in. I can understand parts of the code in isolation, but I lack the knowledge of the frameworks and code that require background understanding. My method of determining whether the code worked was by testing it practically. There were times that I got it to generate test fixtures and tests to ensure that a complex function was doing what I thought it should.
I even then asked Cascade to help me release the plugin. I’ve never needed to make a GitHub release before, but it was a 1-minute conversation to get it done rather than me learning how to use the GitHub command line or somehow do it in the web GUI.
What actually took a long time to release it was the community plugin submission process for Obsidian. It’s pretty rigorous, and I had to go back and forth a number of times with the automated code review and then with a human one… this actually took two weeks!
All that really happened was the enforcement of code standards and rules about what parts of Obsidian could be touched by a plugin. I believe this process could easily have been managed by a similar LLM system to Cascade that was integrated into the CI process. It could utilise the specific code standards and rules present in Obsidian’s community plugins submission process to suggest modifications to the submitter for ensuring plugin compliance - I suspect quite easily without human intervention - particularly if one considers the comments made by my human reviewer on my submission.2
Finally, my plugin got approved, and I felt a small sense of satisfaction. I had no idea if anyone would use it, but shortly after it became an approved community plugin, I had a few users star my repo, and a couple made an issue to handle some rough edges from my initial implementation.
V1.0.0 of LLM Tagger had a button to tag all documents in your vault and automatically tagged content added to the vault. Unfortunately, this also included any document you started writing. It stored metadata at the top of each document to say it was tagged and didn’t need to be tagged again, alongside the tags and a generated summary. In order to retag a document, you would delete this metadata from the top of any document.
As might be expected, but not by me, never having had another soul use my software before, users wanted a better UX. The ability to exclude certain files and folders from being tagged. To have currently open files not be tagged while in use and then tagged after being closed. I was busy with work for a few weeks after the issue was raised, but I finally got around to it on a Friday evening. I now sympathise with Jake Thomas when we were working on Buz, and he would take a while to review PRs!
On the first try of adding some features, Cascade seemed to fail. Every time it said it had made the required changes, reinstalling the plugin locally, I could see that the new functionality hadn’t been implemented. It turns out it was due to the initial implementation.
The processes for automatically tagging and manually tagging in batch were separate in the code, so both had to have the new exclusion function use included, and Cascade had only changed one because I hadn’t been specific. This took me a while to figure out.
I ended up reading the code to see what had changed and then asking Cascade whether it had applied the exclusion function before or after the tagging process, as doing it after would be too late… This then triggered Cascade to tell me about the difference between what it called main bulk tagging and auto-tagging and to inform me that the exclusion logic hadn’t also been applied to auto-tagging, which is what I had been using to test it!
Going through this bug-and-fix process, even with Cascade still driving code changes, helped me better understand how the plugin works. It also made me realise how much work goes into open-source projects! An Obsidian plugin is a very lightweight piece of software, too, so I can only imagine how much work maintaining a full platform would take!
I’m not certain if the Typescript written by Cascade is that great or if it has repeated itself loads of times (which seems unlikely, given that it all fits into 700 lines), but I know it functions as intended. I could take the time to understand what each line of code does… but I shan't.
I specifically wanted to know what it was like to build without knowing how the code worked, unlike when I used Cascade to build data pipelines with dlt or the Cube yaml generation to put into SQLMesh, where I knew what the code was doing even if I didn’t write it. Since building this plugin, people have given this kind of development a derogatory name: “vibe coding.”
I don’t feel negatively about this, though. There are so many things of moderate complexity, like this plugin, that could be built by someone who knows what good looks like and can describe this to something like Cascade. Over time, I’m sure this will extend to more complex things.
I have recently been evaluating data classification tools for GDPR compliance, and I’ve considered that this is precisely the kind of tool that could be developed by a vibe coder in the future. After all, if you’re doing it for your company, it doesn’t require hundreds of integrations; it only needs a handful that fit into your toolset. Generating the regex rules for checking for PII isn’t that complex, and trying permutations of fields on sample data to check for PII groupings is also not particularly difficult to construct.
The idea is not to create something that many companies could generically use but to develop something simple and cheap that serves your company in far less time than it takes to select a vendor, allowing each company to do the same. It may even be disposable software you use for a while, and then discard once you’ve completed the task. If you need to do it again, you can recreate it with the new AI of that era and likely achieve something even better with less effort.
I can’t see how this doesn’t reduce the value of software. Even complex software that supposedly has a moat in its product depth will be outcompeted by small, quick, cheap, simple, and disposable software for a specific company context. When you build it in your company’s infrastructure and run it there, you skip many security evaluation hurdles.
However, reducing the value of software is not the same as reducing the value of software engineers. Vibe coded software, when built by a skilled engineer, isn’t really vibe coded; it begins to feel like where an EM has overseen software built by a team of junior to mid-level engineers. It’s Jevon’s paradox again; we’ll make more stuff. Software eventually becomes disposable, or, to put it another way, generated on the fly for a given time and use case.
Sure, there will be deep tech where every bit of performance in a complex engine cannot afford to be built in a sub-optimal way. However, as you’ve seen with some of my projects which used DuckDB and Polars, AI-generated software will import and use these things.
What does this mean for Data Engineering, where we were mostly using frameworks and tools and stitching them together? It makes it even more ripe for some vibe coding, except it’s code that’s easy for us to read and know in its entirety. There is less OOP and config passed around the code, and more sequential scripts. If we know what the code does fully, then it’s not vibe coding at all…
Obsidian is a popular notetaking app that is easily extended using official and community plugins.
One contrary point to this is what they checked and didn’t discuss in the PR because they checked it, and it was fine. I don’t know if they tried the plugin to see if it functioned. It would seem impossible, given the volume of submissions they receive.
I've recently noticed the term "vibe coding" on LinkedIn. I believe the satisfaction derived from creating a solution to a problem is more significant than any label.