In this guide
Why Most AI Coding Specs Fail
Here is what most developers actually send to Cursor or Claude Code:
Build me a task management app. Users can create tasks, mark them complete, and organize them into projects. Use React and Node.js.
This isn't a spec — it's a wishlist. And the AI will fill every gap with its own assumptions. When the output doesn't match what you imagined, it feels like the AI failed. But the AI just solved a different problem than the one in your head.
The fundamental issue: AI coding tools are translators, not mind-readers. They translate written specification into code. The quality of the translation is bounded by the quality of the input.
What "vague" actually costs you
- Sessions that produce the wrong architecture (you wanted SQLite, it built PostgreSQL with Prisma)
- Features that technically work but solve a different user problem than you had
- Context that drifts across a long session — the AI forgets what you said in the first message
- Refactoring cycles that eat the time you saved by using AI in the first place
The key insight: A spec is not documentation written after the fact. It is a briefing written before the session — a transfer of your mental model into a format the AI can execute against without guessing.
What AI Tools Actually Need in a Spec
AI coding assistants process your spec from top to bottom. They are looking for five things:
- What problem are we solving — the context that makes all subsequent decisions make sense
- What the output should do — behavior, not appearance
- What is explicitly out of scope — what to not build (as important as what to build)
- What technical decisions are already made — so it doesn't re-decide them
- What "done" looks like — acceptance criteria the AI can check its own work against
Notice what's not on the list: "make it look nice," "be intuitive," "good UX." These are signals without meaning to an AI. Include them if you must, but they will not drive behavior the way concrete criteria do.
The Full Spec Template (Copy-Ready)
Copy this entire block. Fill in the bracketed sections. Paste it at the start of a new Cursor session, Claude Code conversation, or into your CLAUDE.md file.
# PROJECT SPEC ## Problem Statement # Who has this problem: [Specific user type — be narrow. "Solo developers" not "developers"] # What is the exact pain: [The specific moment of frustration. What are they doing right now that's broken or missing?] # Why current solutions fail: [What do they use today? What's wrong with it?] ## Solution # One sentence: what does this product do and for whom? [Product name] is a [type of thing] that lets [target user] [core action] without [the thing they hate doing]. ## MVP Scope # Core features (maximum 5 for MVP): 1. [Feature 1 — describe behavior, not UI. "Users can X" not "a page with Y"] 2. [Feature 2] 3. [Feature 3] 4. [Feature 4 — if needed] 5. [Feature 5 — if needed] # Explicitly NOT building in MVP: - [Thing you might think should be here but isn't] - [Another thing that seems obvious but is scope creep] - [Authentication/payments/etc if not needed for MVP] ## Technical Architecture # Stack (decisions already made — do not change these): - Language: [Python / JavaScript / TypeScript / etc] - Framework: [Flask / FastAPI / Next.js / Express / etc] - Database: [SQLite / PostgreSQL / MongoDB / etc] - Hosting: [Fly.io / Vercel / Railway / etc] - Auth: [None / Clerk / Auth0 / custom JWT / etc] # Data models: [Model 1 name]: [field: type, field: type, ...] [Model 2 name]: [field: type, field: type, ...] # Key API routes (for web apps): GET /[route] — [what it returns] POST /[route] — [what it accepts and does] [etc] # External services/APIs (if any): - [Service name]: [what it's used for] ## File Structure # Expected project structure: /[root] [file/folder]: [purpose] [file/folder]: [purpose] ## Conventions # Naming and patterns (AI should follow these without being asked): - [Convention 1: e.g., "snake_case for Python files, camelCase for JS"] - [Convention 2: e.g., "All API responses include {success: bool, data: ...}"] - [Convention 3: e.g., "No external CSS frameworks — vanilla CSS only"] ## Success Criteria # What does "done" look like? (Make these testable): - [ ] [Criterion 1: something the AI can verify — "POST /generate returns JSON with keys X, Y, Z"] - [ ] [Criterion 2: a user can do X in fewer than Y steps] - [ ] [Criterion 3: the app runs locally with a single command] ## What NOT To Do # Common AI mistakes to prevent on this project: - Do NOT add [thing that AI commonly adds but you don't want] - Do NOT use [library/pattern to avoid] - Do NOT add authentication unless explicitly asked - Do NOT change the tech stack decisions above
Section-by-Section Breakdown
Problem Statement — why it needs three parts
Most specs skip the problem and jump to the solution. This is the single biggest mistake. The problem statement exists to give the AI the context it needs to make judgment calls when your spec doesn't cover a specific situation.
When Claude Code hits an ambiguous decision — "should this field be nullable?" — it looks back at the problem statement to infer the right answer. Without it, it guesses based on its training data defaults, which may not match your context.
"A tool for developers to manage their projects."
"Solo developers using Cursor who start sessions with a rough idea and end up with code that doesn't match what they needed — because they never forced themselves to be specific before coding."
MVP Scope — the NOT list is as important as the list
AI coding tools have absorbed millions of apps. When you say "task manager," they have a default schema for what a task manager includes: user accounts, teams, comments, tags, due dates, priority levels. Most of those aren't in your MVP.
The NOT list prevents scope creep before it starts. It tells the AI: "I know this exists. We are deliberately not building it."
"Features: task creation, completion, project grouping."
"Features: task creation, completion, project grouping.
NOT building: user accounts, team collaboration, due dates, email notifications, mobile app, tags/labels."
Technical Architecture — lock in your decisions
The stack section is a lock, not a suggestion. If you write "Flask" and the AI decides to use FastAPI because it's more modern, you now have a refactoring problem. Mark your tech decisions as decisions, not preferences.
The data models section is one of the highest-value parts of a spec. Getting your models right before coding starts prevents entire refactoring cycles. Spend extra time here.
Data model tip: Write your models in pseudo-code, not actual code. The AI will translate them into your chosen language. Focus on the relationships and field types, not the syntax.
Conventions — the invisible rules
Every codebase has implicit rules: what you call things, how you structure responses, what you consider a dependency worth adding. Without the conventions section, the AI invents its own conventions, which may be perfectly valid but inconsistent with the 50 files you already have.
Three to five conventions is enough. More than that becomes noise. Focus on the ones where inconsistency would genuinely bother you.
Success Criteria — give the AI a way to check its own work
Write your success criteria as testable checkboxes. "The user experience is good" is not testable. "A user can generate a spec in under 90 seconds from the landing page" is testable.
These criteria also serve as your session goal-setting. When you paste this spec and the AI says "I've implemented that," you can check against this list instead of just eyeballing the output.
What NOT To Do — prevent the patterns you hate
Every developer has learned which AI behaviors frustrate them. Use this section to codify those. Common ones:
- "Do NOT add TypeScript types — we're staying in plain JavaScript for now"
- "Do NOT use external component libraries — vanilla HTML/CSS only"
- "Do NOT create a separate service layer — keep it flat"
- "Do NOT add error handling for every edge case — just the happy path for MVP"
Real Example: A Complete Filled Spec
Here's the template filled in for a real project — a simple URL shortener:
# PROJECT SPEC — QuickLink URL Shortener ## Problem Statement Who has this problem: Solo developers and indie makers who need to share links in demos, blog posts, and social media. What is the exact pain: Long URLs in blog posts look ugly and break in email clients. Existing shorteners (bit.ly) require accounts, track clicks for surveillance purposes, and are overkill for personal use. Why current solutions fail: bit.ly requires signup and their free tier limits customization. Building your own feels complex. No self-hosted option is simple enough to deploy in under an hour. ## Solution QuickLink is a self-hosted URL shortener that lets indie developers create short links without accounts, paywalls, or surveillance tracking. ## MVP Scope Core features: 1. Paste a long URL, get a short URL back (no account required) 2. Short links redirect to the original URL 3. Admin page (password-protected) to see all links 4. Click count tracking per link 5. Custom slug support (optional, 3-30 chars) NOT building in MVP: - User accounts or authentication for link creators - Link expiration or deletion - QR codes - UTM parameter injection - Team features - API ## Technical Architecture Stack: - Language: Python - Framework: Flask - Database: SQLite (single file at ./links.db) - Hosting: Fly.io (free tier) - Auth: None for creating links; ADMIN_SECRET env var for admin page Data models: Link: id (int), slug (text unique), target_url (text), created_at (text), click_count (int default 0) API routes: GET / — returns index.html (the form) POST /shorten — accepts {url, slug?}, returns {short_url} GET /{slug} — redirects to target_url, increments click_count GET /admin — returns admin page (requires ?secret=ADMIN_SECRET) ## File Structure /quicklink app.py — Flask routes and SQLite logic templates/ index.html — the shortener form admin.html — admin link list fly.toml — Fly.io config requirements.txt — flask, gunicorn ## Conventions - No external Python packages beyond Flask and gunicorn - Vanilla CSS in <style> tags — no external CSS frameworks - All responses from /shorten return JSON: {success: bool, short_url?: str, error?: str} - Admin secret read from environment variable ADMIN_SECRET ## Success Criteria - [ ] Paste a URL into the form, get a short link back in < 2 seconds - [ ] Short link redirects correctly 100% of the time - [ ] Click counts increment on each redirect - [ ] Admin page shows all links when correct secret is passed - [ ] App runs locally with: pip install -r requirements.txt && flask run ## What NOT To Do - Do NOT add user authentication for creating links - Do NOT use SQLAlchemy — raw sqlite3 only - Do NOT add Bootstrap or Tailwind — vanilla CSS - Do NOT add email sending - Do NOT create separate services/blueprints — keep everything in app.py
Common Mistakes That Waste Sessions
Mistake 1: Describing the UI instead of the behavior
AI tools build behavior from specs. When you describe the UI, they have to infer the behavior — and they often infer a more complex version than you meant.
"A sidebar with a list of projects on the left, a main panel showing tasks on the right, and a top bar with filter buttons."
"Users can switch between projects. The selected project shows its tasks. Users can filter tasks by status (all/active/done)."
Mistake 2: Leaving the stack implicit
If you don't specify your stack, the AI will use what it would use. That might be TypeScript instead of JavaScript, PostgreSQL instead of SQLite, or a component library you've never used. Always be explicit.
Mistake 3: Saying "simple" or "lightweight"
These words mean different things to different developers. To an AI, "simple" might mean "no TypeScript" or it might mean "fewer than 10 routes." Replace these adjectives with constraints:
"Keep the architecture simple and lightweight."
"Everything in a single app.py. No services layer. No separate modules for MVP."
Mistake 4: Not reading the output before the next prompt
The most common session drift pattern: you give a spec, the AI produces code, you ask for the next feature without checking what it built. The AI assumes its previous output was correct and builds on top of it. Small mismatches compound.
After every significant generation, verify the output against your success criteria before asking for the next thing.
Mistake 5: Updating the spec mid-session without acknowledging it
Requirements change — that's fine. But when you change a requirement mid-session, explicitly tell the AI: "Changed requirement: X. Previous implementation of X should be replaced with Y." Don't just ask for the new thing and hope it infers the replacement.
Generate Your Spec in 30 Seconds
Paste your rough idea. SpecForge outputs a complete spec package — PRD, GitHub tickets, and a CLAUDE.md file — structured exactly for AI coding tools.
Generate My Spec →