(Personal note: A mouthful of a title, I know – but hey, a long title for a long post seemed fitting to me)
Table of Contents:
Common Pains of AI Coding
Not to trigger pseudo-PTSD in anyone, but here’s a list of things that drove me nigh-insane when I first started vibe-coding (across both Repit and Claude Code):
- AI conducting endless debugging that feels circular, like a dog chasing its own tail
- “Now that I’m finally reading the logs… didn’t we already try this exact same fix three iterations ago? Actually, wait, why do we even need to fix this when it’s an intended functionality!?”
- AI forgetting critical context or “getting lost in the sauce”
- “Why did my app for pet owners randomly create ‘Dog’ and ‘Cat’ as new potential profile type options?
- AI introducing N > 1 ways to solve the same exact problem
- “Why do I have three libraries to visualize charts? Why are these three libraries causing compatibility issues? Oh god, I have to consolidate and refactor the code.”
- AI removes a piece of problematic code since it’s not used by the focus of the current sessions, but forgets that said piece of problematic code is critical to the broader platform
- “Wait, did we just remove the requirement to be authenticated because it threw a couple of errors? Why would you remove instead of fixing the error? Hello?”
I’m sure there are plenty of cases beyond what I listed above – these were just ones that I distinctly remember (and sometimes still deal with). As my last post highlighted, context makes all the difference when vibe-coding. Despite implementing the lesson I learned, I found myself still encountering the challenges above once conversation histories became lengthy or the codebase grew large enough.
Naturally, I started asking: “There must be a better way for this, right?” Without access to some of the more enterprise-grade context-management solutions, what can a humble individual pursuing passion projects do to remedy this issue?
After a lot of researching (the usual forums posts, helpful YouTube videos, Reddit threads, and cringe YouTube videos) and manual testing, I found a solution that works well for my purposes.
This post sheds light on the problem and describes how you can avoid these migraine-inducing issues (or “avoid more of,” if you’ve already been tinkering).
The Solution to the Common Pains of AI Coding
The answer lies in creating pre-development documentation as markdown files (.md files). Think of these as persistent context files that can be referenced at any time by your vibe coding tool and are applicable across both sessions within the same tool, as well as across tools (if you choose to start over or try with another tool).
While they can take some time to develop, I’ve found that it provides all of the following:
- Helps keep the actual development process focused on a north star
- At any point, you can refer back to these files in a prompt (or embed it directly into the CLAUDE.md file, which I talk about later) to maintain context across sessions.
- Reduces the amount of interpolation that LLMs have to do
- Rather than saying “Hey Claude/Gemini/ChatGPT, find me a route from A to Z!” (in which case, it might come up with 100 different routes), you’re more so saying “… find me a route from A to Z that passes through [B/C/D/E/…] – evidently, the latter leaves less room for error and unanticipated results.
- Helps you clarify goals and prevent yourself from scope-creeping (i.e., letting your creativity go haywire)
- As you’re brainstorming through required vs. nice-to-have features, you’ll be forced to read through just how much you are asking for from these vibe-coding tools. If you find yourself staring at a 12-page long “required functionality” doc – you probably have a whole lot of non-required functionality mixed in there.
Interestingly, this is nothing novel and I certainly didn’t invent this concept. In fact, I first came across markdown files when I saw a ‘replit.md’ file in the directory of one of my Replit apps. I didn’t think much of it at the time and never clicked into it, thinking it was just a marketing tactic to have Replit’s name show up in every GitHub repo created with it.
Imagine my surprise when I was researching Claude Code and realized everyone was referencing the CLAUDE.md file – some gears started turning. “Maybe ‘replit.md’ was actually used to manage context in Replit as well…?” As I went to some of my Replit apps to finally open these .md files for the first time, I realized this was the missing piece all along: augmenting the vibe-coding apps’ existing context files with my own.
Introduction to CLAUDE.md and Markdown Files (.md files)
For those already using Claude Code, or who have done their due diligence on it, you’re likely familiar with the CLAUDE.md file. As Anthropic describes it, “CLAUDE.md is a special file that Claude automatically pulls into context when starting a conversation” – almost like a persistent set of instructions and/or context that you want to start each session with (Anthropic, “Claude Code: Best practices for agentic coding”).
There are countless guides, YouTube videos, Reddit posts, and even GitHub repos (more on that in a later post) that share best practices on both what to include in your CLAUDE.md file as well as how to structure it. As such, I won’t dwell too long on it, but here is a sample of what I typically include in mine:
- Project Context
- Technology Stack & Architecture
- Directory Structure Guide (especially if I have pre-development documentation files)
- Key Business Logic & Conventions
- Development Workflow / Phases (e.g., what’s MVP vs. post-MVP)
- Reminders
- Rules / Restrictions / Requirements
- Links to Key Documentation & When to Use (typically for pre-development documentation files)
- Environment Configuration
I’ll get into this more later on, but I would recommend you DO NOT start with creating a CLAUDE.md file off the bat. Rather, I would recommend you create pre-development documentation as markdown files (.md files) before diving into the Claude side of things.
Speaking of markdown files…
Obviously, I had done my own research into Claude Code before choosing to invest time into it on top of Replit and other vibe-coding tools. Inevitably, I had come across CLAUDE.md before, but I’d be lying if I found Anthropic’s post above on my first search. Somewhat embarrassingly, my first Google search was actually: “what is an .md file?” I’m being dead serious when I say I actually thought it was a new coding language specific to AI and LLMs that I completely missed despite my ever-trusty Google app constantly surfacing relevant content for me to read.
Digging a little deeper, I quickly realized these .md files weren’t a new coding language at all. In fact, these markdown files (.md files) quickly became my favorite file type due to how readable and structured they often were. Of course, they could provide instructions and context (given CLAUDE.md is itself a markdown file), or they could serve as documentation and notes, similar to a traditional text file. The only difference is that markdown files support syntax, which both helps with readability and with LLMs’ ability to interpret instructions.
Since much has been written about this, you can check out this Basic Syntax guide for more details. As for what I believe to be most important for vibe-coding purposes:
- Heading Levels – We often rely on bolding / spacing to separate sections in our writing. Unfortunately, as of writing this, Anthropic’s Claude seems to be the only one out of the big three that actually supports text formatting within its chat window (side note, neither does Perplexity). So if that’s the case… how can we ensure that ChatGPT and Gemini are actually associating the right instructions to the right topics / sections? How do we bridge what we see as a no-brainer to what an LLM would interpret as just another sequence of tokens?
- Enter, Heading levels. There are numerous prompt engineering frameworks out there, such as C.O.R.E. (Context, Objective, Role, Example) and T.R.A.C.E. (Task, Request, Action, Context, Example). Still, you’ll quickly notice that most example prompts using these frameworks leverage heading levels to separate each of the letters in the acronym.
- Bolding Words – I typically use bolding (which looks like **this** wherein “this” would be bolded) when instructing Claude Code to **NOT** do something. Probably my most common use case is: “Do **NOT** edit the codebase. This is strictly a read-only audit of [X].”
- Lists – pretty straightforward on this one: Use numbers plus periods for ordered lists and hyphens for unordered lists. The only mildly annoying thing about this is if you’re like me and often number lists with parentheses (e.g “1)” or “2)” and so on), it’s going to take a little bit of getting used to.
- Code Blocks – Personally, I do not like being prescriptive with Claude Code since I’m not technical enough to be prescriptive. More often than not, I lead Claude Code astray. However, if you’re more familiar with and confident in the technicals, you can clearly indicate what is meant to be a code block and what isn’t. The less you need to rely on Claude Code to interpret your text input, the more likely that it’ll actually do or deliver what you want it to.
Of course, there are many more nuances to markdown syntax than just the above, but that’s not the focus of this blog post. Instead, I just wanted to provide a quick overview for those who might not have encountered them in the past.
Diving into Pre-Development Documentation for AI
As a non-technical individual, I’ve found that pre-development documentation is the one step that I absolutely cannot skip. With these, my projects usually make real progress, if not reach completion. Without these, I usually get stuck in debugging rabbit holes, deployment (and redeployment) hell, and hallucinations galore. This is especially the case as the codebase gets bigger or chat histories get long.
Furthermore, excellent pre-development documentation also provides you with flexibility. There’s no need to be tied to the conversation history of a specific vibe-coding tool you’re using. If you find that your current tool is insufficient, the rational decision would be to try something else (fake shoutout to my Economics degree, since I wasn’t the best student). Rather than having to start from scratch, your pre-development files (where most of the context is laid out already) allow you to leapfrog the initialization pains and, sometimes, even one-shot most of your app from scratch.
I actually provide an example of precisely the above at the bottom of this post under “Final Words”
Below are some of the questions I had when I first came across the idea. I’ve also included my non-technical responses. Although they’re from a non-technical perspective, it’s based on countless trial-and-error experiences that hopefully you’ll be able to avoid.
A. So what are these pre-development documentation files you speak of?
In a nutshell, I’m talking about scoping out the project before development begins. Despite not having worked a day in construction, I would liken it to creating the blueprints, deciding on materials, and designing the layout of a new-build house before bringing in the workers. Side note, I watched my childhood home get built from the ground up, which is where the inspiration for this analogy came from.
These pre-development documentation files help paint the picture for Claude Code and also limit the amount of decision-making that Claude Code needs to do. I view Claude Code as a delicate daisy chain going from your idea and inputs to the ideal output and final product. Each additional link makes the whole chain weaker, and every time you rely on Claude Code to make a decision in the middle of an action (e.g., it has to decide what libraries to use for an implementation in the middle of implementing said feature), the less likely you are to get an error-free result.
Layering onto the prior topic, the easier it is for Claude Code (or really, any other LLM) to interpret your documentation, the greater the likelihood that things are done without too many hitches. I’m not promising zero, though – that’s nearly impossible.
To the degree that I can, I limit vibe-coding tools’ scope to pure implementation where possible, and a large part of how I do this is through the pre-development documentation.
B. What pre-development documentation files should I make then?
If you had asked me in May 2025, I would have given you one answer. If you asked me in June, I would have given you different answer. And if you asked me right now, I’d give you another answer still. I’m not saying this to say that I am fickle-minded.
In truth, back then, I couldn’t accurately anticipate what my project would require on the implementation side. I was also worried that by being too descriptive in the pre-development documentation, I would be too prescriptive toward Claude Code and lead it astray (similar concern to the “Code Blocks” section above). However, as time passed and I pursued more passion projects, both of these factors became less of a barrier; therefore, my answer has evolved.
If you’re creating pre-development documentation for the first time, it’s fine to keep it simple, such as a PRD.md (Product Requirements Document). In fact, that’s also where I started. Nevertheless, several “let’s just start from scratch” moments of frustration later (i.e., I started the same passion project anew), I’ve since expanded the collection of pre-development docs that I make before the shovel meets the ground, so to speak.
For context (pun intended), here’s a tree from my current passion project’s root folder (stored in `docs/`):
docs
├── design
│ └── DESIGN_SPEC.md
├── legal
│ ├── PLATFORM_POLICIES.md
│ └── TERMS_AND_CONDITIONS.md
├── product
│ ├── CONTENT.md
│ ├── FAQ.md
│ ├── PRD.md
│ ├── SITEMAP_IA.md
│ ├── USER_FLOW.md
├── security
│ └── SECURITY.md
└── technical
├── DATABASE_SCHEMA_ERD.md
├── DEV_PRIORITY_GUIDE.md
├── OAUTH_SECURITY_FLOWS.md
├── TECH_SPEC.md
└── VERSION_CONTROL_DOC.md
To clarify, within `docs/` I have several folders, and within the folder groupings, I have the pre-development docs (all of the .md files).
Some of the above may not apply if your project doesn’t require things like legal or OAuth, but I’ve found that the following are my personal must-haves:
- PRD.md – your core product requirements
- TECH_SPEC.md – your technology stack, architecture, API setup, etc.
- DATABASE_SCHEMA_ERD.md – your database schemas
- DESIGN_SPEC.md – overall look+feel and guiding design principles (there’s the marketer in me)
- CONTENT.md – if you have specific text or guidance for text (e.g., email templates)
- USER_FLOW.md – expected average user flow (or the ones you care about the most)
- SITEMAP_IA.md – If your web application has multiple pages, it’s helpful to define them upfront
Honestly, if you asked me in another 1-2 months, I wouldn’t be surprised if a new addition (or several) join the list. For example, I regret not having created a “BUSINESS_MODEL.md” document before I started my current passion project. Just going through the brainstormin / ideation phase would force you to consider all parties / stakeholders involved if your project were an external one intended to eventually generate revenue. In the case of my current passion project, I wanted to learn how to integrate Stripe since I had never dealt with it before, so I regret not having scoped out a “BUSINESS_MODEL.md” beforehand.
Of course, each person and project will differ, so please view the above as general advice and lessons from my experimentation, rather than gospel.
C. How do I create them? Are you asking me to become technical and a novelist?
No – as much as I’m blogging again to get back into writing, I’m not so masochistic that I want to be spending a week or two just writing pre-development docs between 8 PM and 2 AM Pacific Time for a passion project. Especially with how work picks up anywhere betwen 6 AM and 8 AM these days, I don’t even think a masochist would enjoy that.
My process for creating pre-development docs involves roughly:
- 10% typing in what I want
- 80% reading the outputs from various LLMs
- 10% making edits, clarifying questions, prodding the LLM for further clarification, etc
Of course, this is just my process and it varies from person to person (and even from project to project).
For technical questions and remarks like “I don’t know libraries, much less which library to use for a specific function!?” – don’t worry. After all, we are in the age of AI. Unlike traditional Google searching, you can just send whatever you have decided on already into an LLM and ask, “What would be the best library for [X] that’s the easiest to implement for MVP purposes?” and you’ll get a slew of recommendations.
All that said, here’s my summary of how to create pre-development documentation:
- Choose your favorite brainstorming companion: My “bias” is toward Gemini since my personal experience is that it’s less sycophantic than ChatGPT and Claude. Usually, I have some semblance of an idea and I’m taking it to my “bias” (this is a K-pop reference, by the way) to see what direction I want to take it while still being reasonable achievable.
- Begin brainstorming with your idea: This phase depends heavily on how baked (or half-baked) your existing idea is. This isn’t Y Combinator after all – concepts like “tarpit” ideas and founder-market fit don’t apply when you’re just tinkering around. Whether your idea is a classic “hello world” page, a dad-jokes engine, or it’s something that’s actually work-related – I don’t think there’s any downside in giving it a shot.
- Turn idea into PRD_v1: Once your idea is fully baked, request your bias to ask any final clarification questions it may have after all of the brainstorming. Answer any questions it may have, and then ask it to generate your PRD_v1 in “markdown syntax within one code block” to make it easier to copy and paste elsewhere. I’d recommend spelling PRD out just in case.
- READ PRD_v1 & Edit: This is incredibly important and often overlooked, especially if you have the tendency to trust AI to the degree of blind confidence. Actually read the PRD_v1 and treat it as the foundation of the house – if it’s botched, so will the rest of the house. Make corrections, adjustments, tweaks, or complete rewrites as needed. This can either be done in coordination with your preferred LLM or directly within a text editor.
- Create the other pre-development docs: Once you have created the PRD_vF.md (vF as in “version Final” – a callback to my Finance days), you should start a new chat, upload the file, and ask it to create the remaining pre-development docs, starting with TECH_SPEC.md. I prefer to start with TECH_SPEC.md followed by DATABASE_SCHEMA_ERD.md (if needed), since they form the basis of your application’s backend. Of course, TECH_SPEC.md often includes frontend specifications as well. However, I’ve generally ended up in more debugging rabbit holes with the backend, so I take care to read through and ensure that these two critical files are in good condition before proceeding with the rest.
It’s a classic “go slow to go fast” process that feels painful in the moment but pays dividends down the line. I also understand that it’s somewhat antithetical to the “deliver a wow moment within five minutes of using it” experience that vibe-coding has become synonymous with.
Note that in my summary above, I’ve avoided including the countless reading, iterating, and clarifying that may actually be involved. I would expect this process to take between an hour for a small web app to several hours for a fully functioning app (assuming no breaks). You want these pre-development docs to serve as the “north star” throughout the development process and a well-designed set can save you countless hours later on.
I understand this can be a little abstract, so let me know if screenshots would be helpful – always happy to supplement this post with examples and sample prompts, if needed.
What to do After Creating Pre-Development Docs
Assuming that you’ve already installed an IDE with a terminal (e.g. Cursor, VS Code, etc.), and Claude Code, the rest is a breeze. If you haven’t yet, I’d recommend this guide, watching setup videos on YouTube, and asking LLMs for specific guidance on problems that you might be running into! Candidly, I’m only familiar with my current environment, so I don’t want to overstep and potentially lead you astray.
After your pre-development docs are created, do the following:
- Create a new folder for your passion projects (if you don’t already have one)
- I would highly recommend against using spaces in any of your folder names – Claude Code often has problems with executing bash commands when paths contain spaces in them. Hyphens, snake case (underscores), and camel case (e.g. likeThisFormat) all work much better. For example, I previously had a folder called “AI Projects” that cause so many permission requests that I eventually just cloned my passion project’s repo into a new “aiProjects” folder – unnecessary permission requests from Claude Code immediately dropped by 80%.
- Create a folder for your new idea (again, no spaces in the folder name!)
- Create a “docs” folder within the new idea’s folder
- You do not have to follow the structure that I used for my passion project. I just structured it like that since it was easier for me to track within Cursor’s file navigation menu.
- Open the project in your IDE of choice so that you’re already in the correct folder
- Activate Claude Code (enter ‘claude’ in your Terminal within Cursor) and then enter the slash command ‘/init’
- Since you should only have your pre-development documents in the project folder at this point, Claude Code should establish a strong understanding of the project vision, it’s product requirements, and the rest of what is needed to bring the idea into reality!
- After the ‘/init’ command has finished and the CLAUDE.md for your project has been created, I also like to update it with links to the pre-developement docs and when to refer to them. This can be a simple prompt in Plan Mode (shift+tab with Claude Code active to toggle until you see “Plan Mode”):
“Please review all of the files in @docs and update CLAUDE.md with a new “Links to Documentation” section. Group the documentation file by topic area (e.g. Product Documentation, Technical Documentation, etc.) and provide the path links to the files themselves as well as when to refer to them.”
- When starting out, I would definitely recommend abusing Plan Mode if your subscription plan supports the token usage.
If done right, you should have a development-ready CLAUDE.md file with a section in it that looks like the following:
## 9. Links to Key Documentation
### **Product Documentation**
- `/docs/product/PRD.md` - Complete product requirements v2.0
- `/docs/product/USER_FLOW.md` - User journey mapping
- `/docs/product/SITEMAP_IA.md` - Navigation structure
- `/docs/product/CONTENT.md` - Brand voice and messaging
- `/docs/product/FAQ.md` - User-facing questions and answers
### **Technical Documentation**
- `/docs/technical/TECH_SPEC.md` - Complete technical specification v2.0
- `/docs/technical/DATABASE_SCHEMA_ERD.md` - Database design and relationships
- `/docs/technical/OAUTH_SECURITY_FLOWS.md` - Authentication implementation
- `/docs/technical/VERSION_CONTROL_DOC.md` - Git workflow and versioning
### **Security & Legal**
- `/docs/security/SECURITY.md` - Security requirements and implementation
- `/docs/legal/TERMS_AND_CONDITIONS.md` - Platform legal framework
- `/docs/legal/PLATFORM_POLICIES.md` - Community guidelines
### **Design & Content**
- `/docs/design/DESIGN_SPEC.md` - Visual identity and UI specifications
Final Words
And that’s it! That’s the exact process I follow when starting a new passion project. It’s a little tedious, requiring more upfront investment and reading, but it’s become my preferred approach to save a lot of time during development and debugging.
The best part of this approach is that the pre-development docs are “universal” in the sense that you can bring them from one vibe-coding tool to the next, offering you some flexibility if you decide that the current tool you’re using is insufficient.
For example, I took about 3 hours fleshing out the pre-development docs for an ROI calculator that I was working on. It was inspired by work, but really just a passion project of my own since it seemed like a great personal learning experience. I was using Claude Code to develop it, but at some point, I was curious about whether or not it would be better in Replit. Since I was still developing and using localhost ports to preview and test, I figured Replit’s built-in preview capabilities might be better suited for the stage I was at.
Lo and behold, I fired one quickly-constructed prompt, attached my pre-development docs, and Replit was able to recreate all of the functionality except the chart visualizations:



There is literally no other interaction beyond the initial message I sent – nothing hidden, cut, excluded, etc. Just the beauty of constructing robust enough context and enough pre-anticipated questions answered through the pre-development docs that the Replit Agent could go to town on the implementation.
All of the ROI calculations were correct as well, since the formulas and relationships were all mapped out in the pre-development documents. The only things that were missing were more robust chart visualizations and solid PDF-generation capabilities – both of which I had neglected to provide specific libraries to use in the pre-development docs (read: oversight on my part).
And that’s it! Do let me know via socials (About page) if this was helpful or if more detail, rather than abstraction, would be helpful for future posts.
Leave a Reply