My Vibe Coding Adventure: Building a Note-Taking App with AI
— Carsten Koch
Ever heard of vibe coding? You just give instructions to AI assistants like Grok and Claude and they build all the code based on your requirements. I stumbled across a LinkedIn post by Nicolas Zullo, Senior Product Director at Doctolib.


Nicolas produced a multiplayer flight simulator in a few hours without writing a single line of code. With 500 prompts he produced a game which had 2 million views on X and 50,000 players. He called it "vibe coding." I was impressed and wanted to give it a shot myself. I am currently working on nexflow.it—a note-taking app which uses Generative AI to help you get organized. I thought, let's rebuild it from scratch using this approach. The note-taking app should support markdown, collaboration, media uploads, and an AI-powered "Chief of Staff" feature—using vibe coding. Spoiler: It was a blast, a mess, and a learning curve all rolled into one—a fascinating learning experience.
There is a high risk of ending up with a result like this:

The Project
My goal was a note-taking app that feels like scribbling in a personal notebook—intimate, secure, and intuitive. With markdown formatting, a slash command menu (type
/
for options), @mentions for collaboration, and media previews for images and PDFs. An LLM would auto-tag content (projects, people, etc.), and a "Chief of Staff" feature would schedule meetings to organize your week. Inspired by Zullo's success, I leaned on AI tools—Grok 3 Think and Claude 3.7 Sonnet Thinking—to design and build it in the Cursor IDE. Could vibe coding make this dream a reality? See the result below:
The Process
Step 1: Designing with Grok
I kicked things off by texting Grok 3 Think on my phone during spare moments. My first prompt: "Write a Product Design Document (PDD) in markdown for a note-taking app…" (see the full prompt in my GitHub repo—link at the end). In no time, Grok wrote out a detailed PDD with features like markdown support, real-time collaboration, and automatic tagging.
Next, I asked, "Propose the simplest yet most robust tech stack." Grok's first attempt was solid but missed the editor component and ignored my AWS preference. After a few follow-ups ("Add an editor!" "Make it AWS-centric!"), we landed on Next.js, Tiptap (editor), Yjs (collaboration), and AWS Amplify. To keep things tidy, I had Grok create Architecture Decision Records (ADRs) for each tech choice. These mini-docs justified decisions like using DynamoDB or S3—great for transparency. After two days and a long chat, I had a PDD and 16 ADRs, all refined through casual back-and-forth. I ran into some smaller issues. The app should follow a local-first approach and yet support real-time collaboration. Yjs comes with a strong conflict-resolution but Grok insisted at first to build your own conflict-resolution. After a couple of attempts, we jointly found a good approach that relies on Yjs and includes a WebSocket-based server to support the real-time collaboration.
Time spent: 2 days of phone texting. That's a full design and architecture in less time than it takes to binge a Netflix series!
Step 2: Summarizing with Claude
With my PDD and ADRs in hand, I turned to Claude 3.7 Sonnet Thinking in the Cursor IDE. I asked it to "Write a tech-stack.md file summarizing the ADRs." I pointed Claude to my ADR folder, and it produced a neat summary (
tech-stack.md
). It included some incorrect decisions that were not part of the ADRs—but a second run with specific pointers fixed it.Then, I asked Grok to craft 10 rules for Cursor to follow during development, emphasizing modularity to avoid a monolithic mess. Example rule: "Break features into multiple files—don't let me wake up to a 1,000-line monster!" I moved all of these rules into
.cursor/rules
.Step 3: Planning the Build
I uploaded my PDD, tech stack, and rules to Grok and said, "Create a detailed implementation plan (in markdown) which is a step-by-step instruction for my AI developers. Each step must be small and specific. Each step must include a test to validate correct implementation. It should not include any code, just clear instructions." The result (
implementation-plan.md
) was a 37-step roadmap—think "Initialize Next.js" to "Add Note Version History." I dropped it into an app-design
folder with the PDD and asked Claude, "Is this clear? What's confusing?" Claude fired back questions like, "What should the schema look like? What metadata would you like to store?" I asked Grok to answer the questions and provided these responses to Claude again. After some ping-pong, the plan was airtight.Step 4: Building with Claude
Here's where vibe coding got real. For each step, I opened a new chat with Claude in Cursor and prompted:
"Read all docs in @app-design, proceed with Step 1 of the implementation plan. I'll run the tests. Don't move to Step 2 until I validate. Then document in @progress.md and explain files in @architecture.md."
Claude read everything, gave me CLI commands (e.g.,
npx create-next-app@latest
), and built files step-by-step. After I validated tests, it updated progress.md
(e.g., "Initialized Next.js on 2025-03-19") and architecture.md
(e.g., "page.tsx
: Home page component"). It was like having a tireless intern who never sleeps but occasionally needs a nudge—an intern, not a Senior Developer.The Good
- Time Savings (50-80%): Claude wrote most of the code, slashing my workload. Even when it stumbled, guiding it beat solo debugging.
- Structured Code (Mostly): The modularity rule paid off—files stayed clean and manageable.
- Documentation Gold: Vibe coding birthed
andprogress.md
, tracking every move. I've never had docs this good—it's like documentation-driven development!architecture.md
The Bad
Not all was smooth sailing. I had moments of frustration:

We've all been there before—when we run into issues, debug like crazy for hours or even days, and can't get to the root cause of the problem. So, nothing new, yet the output of new features produced is worth the approach.
In my project, the slash command menu (
slash-command.ts
) was a beast. Tiptap's custom extensions are powerful but lean on ProseMirror's dense docs. Claude struggled, and I spent 2-3 hours tweaking prompts like:"The component's stable, but: 1/ Arrow keys don't stick—the selection jumps back. 2/ Escape should delete the slash and text."
Eventually, we nailed it. Here's a snippet from
slash-command.ts
that Claude produced after iterations:if (event.key === "Escape") {
const slashPos = this.storage.slashPos;
const currentPos = this.editor.state.selection.from;
if (slashPos >= 0 && currentPos > slashPos) {
this.editor
.chain()
.focus()
.deleteRange({ from: slashPos, to: currentPos })
.run();
}
this.storage.isActive = false;
return true;
}
It deletes the slash command text and closes the menu—sweet victory! Still, those hours felt like herding a digital cat.
The Ugly
Vibe coding has its quirks. Sometimes, Claude's code was gibberish—like it was written in Klingon. I'd tweak it (e.g., swapping straight lines for hand-drawn ones to mimic a notebook), only for Claude to overwrite my changes in the next chat. Lesson learned: Fresh chats are key after manual edits. And the ProseMirror docs? A labyrinth. Guiding Claude through them was like teaching a toddler rocket science—funny in hindsight, frustrating in the moment. And, at some point you think:

Summary
My recommendation is to start small and test vibe coding on a tiny project first. Really focus on just instructing the AI to do what you want. It is a behavior that you need to train in order to get the best out of it. Otherwise, you will give up too quickly and fall back to your old ways.
Start with a Product Design Document (aka PDD, here is the prompt I used), even if you work on an existing product and you just release a new feature.
Guide the AI to create a tech stack document that represents your current tech stack. Then create a folder
docs/release/[release-name]/app-design
and put the PDD and tech stack in there. Let the AI build rules for Cursor and the implementation plan.In your first project let the AI adjust the implementation plan based on your feedback. Once your vibe coding mussle is trained, you can start to intervene and adjust the implementation plan yourself. My experience is that I do not like the order of steps the AI proposes. I prefer to finish a major part of the frontend before I start to work on the backend–the AI is mixing up the order of steps.
Conclusion
Would I vibe code again? Heck yes—with caveats. It saved me some time on coding and it produced (mostly) solid code. The biggest advantage for me was that I focused mostly on the product design and the architecture. I let the AI do the heavy lifting on the coding part. As a result, my thinking was much clearer on the user experience, the product, and a good documentation of what I expect the product to do.
Check out my GitHub repo for the PDD, ADRs, and code. Have you tried vibe coding? Share your wins—or epic AI fails. Let's laugh and learn together!
Sources
- GitHub repo of my vibe coding session
- Nicolas Zullo – Vibe Coding A Flight Simulator
- Nicolas Zullo's approach to vibe coding was the inspiration for my own journey and this blog post
- Pavel Polcr – I Built A Fast Running Horse In Just 3 Days
- Vishakh Hegde's personal thoughts about AI and how it changes the way we work
- Arfath M.'s take on vibe coding
About the author
Carsten Koch works at AWS. He brings 20+ years of IT experience, started coding at the age of 11, and dug into productivity methods and tools as a teenager. Carsten is a father of three and happily married for 25+ years. He now builds nexflow.it–a note taking app with AI as a first citizen. Sign up for the waitlist. Connect with him on LinkedIn.