Blog aboutproductivity

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 Zullo's LinkedIn post
Nicolas Zullo's sharing his experience
The video game Nicolas produced
Nicolas produced a multiplayer flight simulator in a few hours without writing a single line of code
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:
Look I built a fast running horse in just 3 days
Software engineers are so doomed ;-)

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:
nexflow.it Demo
A note-taking app completely built with vibe coding

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
    progress.md
    and
    architecture.md
    , tracking every move. I've never had docs this good—it's like documentation-driven development!

The Bad

Not all was smooth sailing. I had moments of frustration:
Looking angry at the code
Not all was smooth sailing
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:
Say Vibe Coding One More Time
Say Vibe Coding One More Time

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

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.

Comments

nexflow.it logo

    Contact us:

    Email: info@nxsflow.com
    (c) 2025 Carsten Koch