Produce a signed-off spec. Weak spec → weak code. Precise spec → precise code.
Lab 4 — StackLog Spec Writing Sprint
75 minutes to a signed-off spec
Everything the AI generates in Labs 5 and 6 flows from what you write here. A weak spec produces weak code. A precise spec produces precise code.
Surface: Antigravity (PM + Architect agents) + your editor
Artifacts: BMAD V6 outputs (prd.md, architecture.md) + an assembled docs/spec.md
The sign-off bar: "Could a stranger build this from the spec alone — without asking any questions?"
⚠️ How this maps to BMAD V6
The facilitator guide describes "write a PRD, then a Tech Spec" with an Architect persona. In BMAD V6 that's two workflows run by two agents:
| What you're writing | V6 workflow | Agent | Output |
|---|---|---|---|
| Project rules (constitution) | project-context.md |
— | project-context.md |
| PRD (the what & why) | bmad-prd (trigger PRD) |
PM (John) | prd.md |
| Technical Spec (the how) | bmad-create-architecture (trigger CA) |
Architect (Winston) | architecture.md |
The content below (StackLog's goals, features, schema, endpoints) is what you produce. The method is V6 workflows. We'll also assemble everything into one
docs/spec.mdas the committed source of truth the later labs reference.
Phase 1 · Setup (7 min)
Step 1 — Confirm BMAD is installed
From your workshop folder (you cloned BMAD last night):
🪟 cd $env:USERPROFILE\stacklog-workshop
🍎🐧 cd ~/stacklog-workshop
Verify the BMAD agents are available in Antigravity (the bmad-help skill, or the agent menu). If not installed, run the BMAD installer now — or use the fallback templates in docs/bmad/.
⚠️ Check current UI: how skills/agents surface varies by Antigravity build.
bmad-helpis the interactive guide if you're unsure of the next step.
Step 2 — Set the constitution (project-context.md)
Before any feature, capture StackLog's non-negotiable rules. Create project-context.md (or run bmad-generate-project-context):
# StackLog — Project Context (Constitution)
## Stack
- Frontend: React + Vite (TypeScript)
- Backend: Express (TypeScript)
- DB: SQLite via better-sqlite3
- Day-1 data source: stacklog-entries.json (MCP store)
## Principles
- Local-first: no external services, no auth, single user.
- Read-only web app in v1 — entries are created by the MCP server, not the UI.
- Every feature must have a measurable success criterion.
- Markdown input only — no rich-text editor.
- Nothing may exceed PRD scope; out-of-scope list is binding.
This is the constitution from Session 10 — it outranks everything and guides every later workflow.
Step 3 — Open the PM agent
Open Antigravity's agent menu, select the Product Manager (John) agent, and run the PRD trigger (the bmad-prd workflow). It will guide you through PRD discovery interactively.
💡 If you prefer manual control, you can still write
docs/spec.mdby hand using the section guides below — the V6 workflow just facilitates it.
Phase 2 · Write the PRD (33 min)
The PRD answers: what does StackLog do, for whom, and how do we know it's done? (The Tech Spec answers how it works — don't mix them.)
Run bmad-prd and work through these five sections. The PM agent challenges assumptions and demands a measurable success criterion for everything.
🎯 Goals
A 3–5 sentence statement: problem, solution, success.
- Problem: "Developers lose insights created during coding sessions — there's no frictionless way to capture them."
- Solution: "StackLog provides an AI-powered capture layer (the MCP server) and a browsable web interface."
- Success: "A developer can retrieve any past insight in under 10 seconds via search or tags."
⚠️ Watch for goals written as feature lists. "Has search, tags, a feed" is not a goal — push back: why does a developer need these?
👤 User Personas
2–3 personas, each with a name, role, frustration, and measurable success state.
- Alex — solo dev, uses StackLog daily to log research/debugging insights; frustrated by losing context between sessions. Success: finds any past insight in under 10s.
- Jordan — team lead, uses it weekly to review team activity; frustrated by lack of visibility. Success: weekly summary surfaces patterns without manual review.
⚡ Key Features
4–6 MVP features, each with a name, one-line description, and a success metric:
- Entry creation via MCP — agent creates entries via
create_entry(Day 1). Success: entries appear in the feed within 1s. - Entry feed — paginated, newest first. Success: loads < 500ms for up to 1,000 entries.
- Tag filtering — click a tag to filter. Success: applies instantly (client-side).
- Full-text search — queries title, content, tags. Success: results < 200ms.
- Weekly summary — entries grouped by day for the week. Success: one click from the feed.
⚠️ "Full-text search" isn't a feature. "Full-text search returns results in under 200ms" is.
🚫 Out-of-Scope (as important as the feature list)
- Multi-user accounts · Authentication/login · Cloud sync/remote storage
- Mobile app · Real-time collaboration · Rich-text/WYSIWYG editor
- Entry editing or deletion (read + create only in v1)
Every item here is a decision that prevents scope creep in Labs 5–6. The codegen agent will try to add auth. This list is your defence.
📏 Success Metrics (project-level, testable in <5 min at the showcase)
- All Day-1 entries in
stacklog-entries.jsondisplay correctly in the web app. create_entryfrom the agent → entry visible in the browser in under 2s.- Search returns correct results across title, content, and tags.
- The app runs with a single start command.
- Generated code passes the Reviewer check — no spec section violated.
✅ PRD sign-off: Goals have problem+solution+success? Both personas have a measurable success? Every feature has a metric? "multi-user" and "auth" on the out-of-scope list? Every metric testable in <5 min? The question: Could a stranger build the right product from this PRD — no questions asked?
Phase 3 · Write the Technical Spec (20 min)
The bridge between what (PRD) and how the agent should build it. Every section is a constraint on code generation. Vague → inconsistent code. Precise → predictable code.
Switch to the Architect (Winston) agent, run CA (bmad-create-architecture). Tell it: "Refer to the PRD — nothing may exceed its scope. Ask clarifying questions on any ambiguous technical decision." Produce these five sections.
1 · React component tree
App
├── Layout (Header: title+nav · Footer)
├── EntryFeed (props: entries[], isLoading)
│ └── EntryCard[] (props: entry)
│ └── TagBadge[] (props: tag string)
├── SearchBar (props: onSearch callback)
└── WeeklySummary (props: entries[], weekStart date)
Tells the agent what to build and each component's props. Without it, the agent invents a structure.
2 · Express REST endpoints
Base: http://localhost:3001/api
GET /entries ?tag=string (optional)
→ Entry[] sorted by timestamp DESC · 200 | 500
GET /entries/search ?q=string (required)
→ Entry[] matching title/content/tags (case-insensitive)
· 200 | 400 (missing q) | 500
GET /entries/week ?start=YYYY-MM-DD (default: Monday this week)
→ Entry[] for the 7-day period · 200 | 500
⚠️ No POST in v1 — entries are created by the MCP server, not the web app. The app is read-only. If someone adds
POST /entries"just in case," point at the out-of-scope list.
3 · SQLite schema
Database: stacklog.db (project root) — migrate on startup if absent
Table: entries
id TEXT PRIMARY KEY -- UUID from randomUUID()
title TEXT NOT NULL -- max 80 chars
content TEXT NOT NULL -- markdown
tags TEXT DEFAULT '' -- comma-separated lowercase
timestamp TEXT NOT NULL -- ISO 8601
Index: entries_timestamp_idx ON entries(timestamp DESC)
Index: entries_tags_idx ON entries(tags)
🔗 The bridge: Day-1 writes JSON (
stacklog-entries.json); Day-2 reads SQLite (stacklog.db). Note a one-time seed/migration: on first run, import the Day-1 JSON entries into SQLite so yesterday's entries display today. (This is the deliberate JSON→SQLite bridge from the StackLog definition.)
4 · File structure
stacklog-workshop/
├── stacklog-mcp/ (Day 1 — MCP server)
│ └── src/index.ts
├── frontend/ (Lab 6 — React)
│ └── src/components/{EntryFeed,EntryCard,SearchBar,TagBadge,WeeklySummary}.tsx
├── backend/ (Lab 6 — Express)
│ └── src/{routes/entries.ts, db.ts, server.ts}
├── docs/
│ ├── spec.md (this file — source of truth)
│ ├── stories.md (Lab 5)
│ └── tasks.md (Lab 5)
└── README.md
5 · Non-functional requirements
Performance: GET /entries < 500ms (≤1,000 entries) · /search < 200ms · initial load < 2s
Data: local only · SQLite via better-sqlite3 · DB auto-migrated on startup
MCP JSON store: ~/stacklog-entries.json (Win: %USERPROFILE%\stacklog-entries.json)
Compat: Node 18+ · Chrome/Edge latest
Ports: frontend (Vite) :3000 · backend API :3001
✅ Tech Spec sign-off: every feature has a supporting endpoint? Every schema field has type+constraint+comment? Frontend/backend separate? Response targets testable? Ports specified? The question: Could a developer implement this without asking a single question?
Phase 4 · Peer review (12 min)
Not about being nice — about finding gaps that cost you time in Lab 6. Every ambiguity surfaced now saves ~10 min of confused code generation later.
Step 4 — Swap specs, run an Architect review
Swap docs/spec.md with a neighbour (push to GitHub and share the link, or paste into a shared doc). Load the Architect agent and review the other team's spec:
Review this StackLog spec as a critical senior engineer. For each section
(Goals, Personas, Features, Out-of-scope, Success Metrics, Component Tree,
Endpoints, Schema, File Structure, NFRs), identify:
1. Any requirement that is ambiguous or unmeasurable
2. Any missing constraint that would force a developer to guess
3. Any inconsistency between the PRD and Technical Spec
4. Any out-of-scope feature that snuck into the spec
Format as a numbered list. For each: quote the line, name the problem, suggest a fix.
Common findings: features without metrics; components without prop types; endpoints without status codes; schema fields without constraints.
Step 5 — Incorporate feedback (5 min)
Update your own spec from the review. Share: "What was the most valuable finding?"
Phase 5 · Commit (3 min)
Step 6 — Assemble and commit docs/spec.md
Consolidate the V6 outputs (prd.md + architecture.md) into a single docs/spec.md (PRD on top, Tech Spec below, ## headings separating them), then:
🪟 cd $env:USERPROFILE\stacklog-workshop
🍎🐧 cd ~/stacklog-workshop
git add docs/spec.md project-context.md
git commit -m "lab4: StackLog PRD and Technical Spec signed off"
git push origin main
✅ Lab 4 complete when
docs/spec.mdis on GitHub. This file is now the single source of truth. Every story, task, and line of code in Labs 5–6 must reference a section of it. Don't change the spec without updating the section.
Troubleshooting (top 5)
- The agent just agrees with everything → the PM/Architect agent isn't really loaded, or your constitution is too soft. Re-invoke the agent; test with "I want to add real-time collaboration" — it should push back via the out-of-scope rule.
- Writing code in the spec → the most common error. Ask: requirement or implementation? "Use
useStatefor search" is implementation; "search updates as the user types, 300ms debounce" is a requirement. Spec holds only requirements. - Spec too short (bullets, no constraints) → ask: can the agent generate the correct endpoint response format from this? If no, add detail. For each section: "what's missing that would force a developer to guess?"
- Git push auth fails → use Antigravity/your editor's built-in Git auth (Source Control panel → Publish/Sync) to handle the browser auth flow.
- JSON vs SQLite confusion → Day-1 store is JSON, Day-2 app is SQLite by design. The spec's schema is SQLite; note the one-time seed from the Day-1 JSON so existing entries appear.
Bridge to Lab 5
The spec is signed off. Next you feed it to the Developer (Amelia) agent and generate user stories with acceptance criteria — the stories that drive every line of code in Lab 6. The spec is the input. Keep it open.
Before Lab 5: keep docs/spec.md open; Lab 5 starts the Developer agent (bmad-create-epics-and-stories); confirm GitHub is up to date.