Adventures in AI-assisted coding
Note: AI moves quickly. This post is from my thoughts from using Cursor over the last few weeks (March and April 2025), but these thoughts may be obsolete by the time you read this. Consider these observations as snapshots of a moment in time; in a few years (or less!), we will no doubt look back and chuckle at how naive and primitive this all was.
I’ve been using Cursor with Claude 3.7 Sonnet over the last few weeks to create a simple web app to allow interacting with your bookmarks in a more natural way. Some takeaways from the experience below. My key realization: “vibe coding” is a great way to get 80% of the way there, but — in this case at least — I had to eventually bring out my traditional programming and debugging skills to get the app working fully. Nevertheless, the power of these tools is amazing, and they are likely only going to get better.
The “bookmarks chatbot app” is very simple:
1. Import a file containing your bookmarks via a web page (only running on a local server right now)
2. For each bookmark, crawl the web page it references, and add the contents to a RAG database
3. Allow the user to enter in a chat message describing the bookmarks they are looking for. Do a RAG DB query for bookmark content that matches the user prompt, and send the augmented query to the LLM via the OpenAI API. Ask the LLM to provide links to the relevant bookmarks.
4. Display the output.
Easy peasy! The working app is below:
Some observations on the experience:
Amazing at initial boilerplate: Cursor was amazing at creating the initial boilerplate code across multiple files — sometimes it felt like magic seeing it write code using a new library in one file, add an install dependency for the library in another file, and call the newly written function from a third file. I found it helpful to use Cursor and ChatGPT Pro in tandem, using ChatGPT to learn more about the technologies that Cursor decided to use — ChromaDB for the RAG database, BeautifulSoup to parse the bookmarks HTML file, etc. Finding out about these technologies in the first place, learning how to use them effectively etc would have taken much, much longer, and drowned me in low level details. “Vibe coding” this part of the app allowed me to get a skeleton app developed very quickly.
Getting confused while debugging: The initial Cusor-generated code had some bugs in parsing the bookmarks HTML file. I tried to get it to fix the problem via prompting, but it never quite fixed the problem — it often felt like it was adding additional duplicated code in multiple places in a frantic attempt to hide the issue (much like an inexperienced programmer would). Eventually, I got tired of looking at the “Oh, I see the problem” Cursor output that did not actually solve the problem, and had to step in and debug the code directly, removing some of the extra cruft code that Cursor had added.
Confusion with library versions: Cursor repeatedly updated the Python requirements.txt file to include old versions of the OpenAI API and other libraries. Eventually, I learnt to reject changes to the requirements.txt file, preferring the version that the OpenAPI documentation said was the latest.
Lacking higher level thinking: Cursor will happily do lower level operations that you ask it to, without stepping back and reconsidering the bigger picture. For example, I initially did not specify that I wanted a RAG database, so it stored the bookmarks in a standard relational SQLAlchemy database. I then added the requirement that the bookmark content should be searchable in a RAG database, at which point it added in a ChromaDB dependency. However, it did not go back and remove the code that inserted the bookmarks into the SQLAlchemy database; so now the bookmarks were stored in both a standard RDBMS and a vector DB. A reasonably experienced human developer would have probably taken as an implicit requirement that the old RDBMS approach should be scrapped when the vector DB requirement was added.
Does not parse terminal output or error logs directly: Cursor needed me to tell it when running the app resulted in an error; with error logs pasted in, it was sometimes able to fix the problem (and sometimes not, as mentioned above). Ideally, an agent would just run the program, observe the output, make the necessary code changes, and re-run the program. Presumably this will be coming fairly soon as AI agents become more powerful.
Overall, using Cursor (with ChatGPT Pro) helped me create a working app far faster than I otherwise would have been able to do; a few hours of work rather than weeks. I was also able to squeeze the development into my schedule, because the AI assistance allowed me to pick up where I had left off much more easily than if I had needed to reload the entire context of the app into my memory each time I started. I have found this to be a significant barrier in previous development efforts; because I can’t generally set aside long stretches of time for development, by the time I have “loaded in” the context of what I’ve done so far into my memory, I’ve almost run out of time.
Despite the drawbacks listed above, this space feels incredibly exciting and full of promise. I can’t wait to see how new tools like OpenAI’s Codex, and more full-featured AI coding agents, change programming in the years to come.