Playbook: MVP Build
Objective
An MVP built as a stack of verified vertical slices on a deployed walking skeleton — where "verified" means you watched each slice work end-to-end, and every subsystem has an explicit, recorded decision about whether it's demo-quality or production-quality. Agents make the typing cheap; this playbook keeps the verification from becoming the bottleneck that silently gets skipped.
When to use
After New Project (rails exist) and Idea to Spec (PLAN.md exists). If either is missing, do it first — an MVP built without gates or specs is where the 80%-demo trap lives.
Inputs required
- The repo from New Project: gates green,
CLAUDE.mdin place. specs/PLAN.mdwith session-sized, verifiable tasks.- A demo date or forcing function — it drives the quality-tier decisions below.
Step-by-step process
1. Vertical slices, not horizontal layers
Build "a user can create an invoice and see it in the list" — route, handler, DB, UI, one test — not "the data layer" this week and "the API layer" next week. Two reasons, both agent-specific:
- Each slice is verifiable end-to-end. You can click it, curl it, demo it. A horizontal layer is only verifiable against your trust in the agent, which is exactly the currency you don't want to spend. Unverified layers stack silent errors that all surface at integration time, in someone else's session, with none of the original context.
- Each slice fits one session. A layer spans the whole system and exceeds any context window; a slice is naturally scoped. This is why PLAN.md was decomposed into slices in the first place.
2. Walking skeleton first — deployed, with CI
Before slice one: a hello-world that is deployed to the real target with CI running the gates on every push. Deployment is the integration risk most likely to eat a surprise week; buy that knowledge when the system is 50 lines, not 5,000.
Read specs/PLAN.md task 1. Set up deployment of the current skeleton to
<target, e.g. Fly.io> : config in the repo, deploy runs from CI on merge to
main, and the health endpoint publicly reachable. Change no application
code beyond what deployment strictly requires. When done, give me the
public URL and the exact command you expect me to run to verify.Open the URL yourself. The skeleton is done when a stranger could see it.
3. Decide quality tiers per subsystem — explicitly, in writing
The load-bearing step. For each subsystem, decide demo-quality or production-quality before the agent touches it, and record it in PROJECT_CONTEXT.md:
## Quality tiers (MVP)
| Subsystem | Tier | Meaning |
|---|---|---|
| Auth | Production | Real sessions, hashing, lockout. Never stub. |
| Billing | Stub | `FakeBillingProvider`, logs charges. Interface real, provider fake. |
| Email | Console | Log to stdout. No provider, no queue. |
| Invoice engine | Production | This IS the product. Full edge cases. |Why written: an agent that doesn't know billing is deliberately a stub will "helpfully" wire in Stripe when a task brushes against it (silent hardening — scope creep plus an unreviewed integration). An agent that sees console-email as precedent will stub auth the same way (silent softening — a security hole). Both moves are locally reasonable; only your recorded intent makes one wrong. With the table in context, tier changes become something the agent must propose, not improvise. See Docs as Memory.
4. One spec'd slice per session
Fresh session per slice, referencing the spec — not a mega-session that accumulates stale context across slices:
Read CLAUDE.md, PROJECT_CONTEXT.md, and specs/007-invoice-creation.md.
Implement task 7 exactly as spec'd. Respect the quality tiers table —
billing stays a stub. Stay within this slice: if you find adjacent
problems, list them at the end, don't fix them. When done, run `make check`
and give me the manual verification steps from the spec.Then run the verification steps yourself before starting slice N+1. This human gate between slices is what keeps errors from stacking.
5. Know when the MVP is done
The MVP is done when the walking-skeleton scenario from your overview spec works for a real user — not when the plan is empty. Leftover PLAN.md tasks are v1.1, and moving them there is a one-line edit, not a failure.
Human review points
- Skeleton deployment — you open the public URL (step 2).
- Quality-tier table — a product decision; the agent may draft the table, only you fill the Tier column (step 3).
- Per-slice verification — you execute each spec's manual check before the next slice starts (step 4).
- Tier changes — any promotion (stub → real) or demotion is proposed to you, spec'd, and the table updated first.
Expected artifacts
Deployed walking skeleton with CI · PROJECT_CONTEXT.md with the tier table · one merged, human-verified branch per slice · PLAN.md with tasks checked off · specs updated where reality diverged (Keeping Specs Alive).
Common failures
| Symptom | Root cause | Early detection | Fix |
|---|---|---|---|
| The 80%-demo trap: demo dazzles, every path off the demo script 500s | Demo-quality everywhere by default, no tier decisions ever made | Try three actions the demo script doesn't include | Step 3: explicit tiers; "production" subsystems get spec'd edge cases like anything else |
| Unverified slices stack; slice 9 breaks and the bug is from slice 4 | Human verification skipped when gates were green | You can't remember personally exercising the last slice | The between-slice gate is non-negotiable; if it lapsed, stop and verify all merged-but-unverified slices now |
| Scope creep via agent enthusiasm: slice adds retry logic, an admin view, "better" error pages | Agent fills slack with plausible adjacencies; each looks like diligence | Diff touches files the spec never mentions | "Stay within this slice; list, don't fix" clause; reject nonconforming diffs — see Scope and Context Failures |
| Stub silently hardened (real Stripe calls appear) or real subsystem silently stubbed | Tier decisions absent from agent context | New dependency or deleted check in a diff that didn't announce it | The tier table in PROJECT_CONTEXT.md, referenced in every implementation prompt |
| Slice "done" but only unit tests prove it | Verification defined as tests-pass, not works-end-to-end | Spec's manual check was never written or never run | Every slice spec names a human-executable check; see Verification Checklists |
Recovery strategy
If unverified slices have stacked, freeze feature work and bisect: verify each merged slice end-to-end from oldest unverified forward, fixing or reverting per slice in its own session. If demo-quality code has quietly become the whole codebase, run the tier exercise retroactively — the table is even more valuable when the promotion work (stub → production) still has to be scheduled honestly. Full agent-mess recovery is its own playbook: Recovery.
Acceptance criteria
- [ ] Skeleton deployed and CI-gated before any feature slice
- [ ] Tier table exists in
PROJECT_CONTEXT.mdand is cited in implementation prompts - [ ] Every merged slice was human-verified end-to-end, not just gate-green
- [ ] No diff touched subsystems outside its spec without an explicit tier-change decision
- [ ] The overview spec's walking-skeleton scenario works on the deployed system
Related
- Idea to Spec — produces the PLAN.md this playbook consumes.
- New Project — the rails this playbook assumes.
- Verification Checklists — the per-slice checks that keep slices from stacking unverified.
- Scope and Context Failures — the enthusiasm-creep mechanism in detail.
- SaaS MVP case study — this playbook run end-to-end, including what went wrong.
- Docs as Memory — why the tier table lives in the repo, not in your head.