Learning objectives
By the end of this module, you will be able to:
- Apply the six-element framework to write a spec that an AI agent can act on without guessing.
- Keep the what and why in the spec and the how in the plan, and place each element in the right section of Spec Kit’s spec template.
- Decompose oversized features using INVEST and MoSCoW so each spec stays human-reviewable.
- Decide what belongs in the project’s constitution and what belongs in a per-feature spec.
- Check a spec before you build on it with
/speckit-clarifyand requirements checklists, and name the gate that catches each of the four most common spec failures.
1.The six-element framework
The strongest predictor of whether a spec produces good agent output is whether it answers six specific questions. If any of them are missing, the agent fills in the gap, usually badly.
All six need answers before an agent writes code, but Spec Kit doesn’t keep them in one file: the spec holds the what and why, the plan holds the how. Section 2 maps each element to its home.
Element 1 — Outcomes when the work is done
Not “build an auth flow.” Closer to: “A returning user with valid credentials lands on their dashboard within 2 seconds of submitting the login form. A user with invalid credentials sees an error message within 1 second and the form retains their entered email.”
Outcomes are observable. They are written in terms of what the user (or caller, or downstream system) experiences. They are not feature names.
A good test: can someone external to the project tell whether the work is done by reading the outcome statement? If yes, you have an outcome. If they need to inspect the code, you have a feature description.
Element 2 — In-scope and out-of-scope
Most engineers remember to write the in-scope list. The out-of-scope list is where specs fall apart.
Agents have absorbed an industry-wide pattern of what auth flows usually look like. If your spec says “users can sign in” and stops there, the agent will probably also build OAuth, password reset, account lockout after failed attempts, email verification, and remember-me cookies — because that’s what auth flows usually have. None of those may be what you actually want for this iteration.
Out-of-scope statements close the door:
Out of scope:
- OAuth / social login
- Password reset (handled in v2)
- Email verification (assumed already done by /signup)
- Multi-factor authentication
- Session timeouts longer than 24 hours
The out-of-scope list is at least as important as the in-scope list, sometimes more. Write it deliberately.
Element 3 — Constraints and assumptions
Anything that shapes the solution and isn’t obvious from the codebase. Constraints are imposed on you from outside; assumptions are statements about reality you’re treating as given.
They come in two kinds. Product-level ones — who the users are, what devices they use, what the feature can rely on — are what, so they go in the spec. Technical ones — the stack, the libraries, a latency budget in milliseconds — are how, so they go to the plan, or to the constitution if they hold for every feature. For the course’s to-do app:
Assumptions (spec):
- One user per browser; no sign-in
- To-dos survive a page reload on the same device; no cross-device sync
- Usable on a phone-width screen (375px) as well as a desktop
Technical constraints (plan or constitution):
- Next.js App Router with React and TypeScript; styling with Tailwind
- Persistence stays in browser localStorage; no backend, no database
- No new runtime dependency without the team agreeing to it
Element 4 — Decisions already made
Things you’ve decided that the agent should not relitigate. If you’ve already chosen a date format, a validation library, a particular pattern from elsewhere in the codebase — say so explicitly.
Without this, agents will reinvent things you already decided. They might pick moment.js when you’ve already standardized on date-fns. They might use Joi when the rest of the codebase uses zod. Each of these reinventions is a small future refactor.
Decisions already made:
- Use ISO 8601 strings for all date fields (no Date objects in JSON)
- Validation errors return HTTP 400 with
{ error: string }body- All new endpoints follow the existing
/api/<resource>pattern
Every one of those is technical, so in Spec Kit it lives in the constitution (project-wide) or in what you hand to /speckit-plan (this feature). The spec keeps only decisions a user would notice — “one comment per order,” “only the uploader can delete a file.”
Element 5 — Task breakdown
Break the work into discrete, verifiable sub-tasks. Each task should be small enough that a single agent run can complete it and a human can verify it without losing focus.
This is the one element you don’t write into the spec. /speckit-tasks generates tasks.md from the plan: Setup, Foundational, one phase per user story in priority order, then Polish. The spec’s job is to be sliceable — prioritized user stories that can each be built and tested on their own. If you can’t see how your spec would break into tasks, it isn’t ready.
Still review and edit the generated task list. Agents tend to produce too-coarse tasks (they’re trained on PR-sized chunks), and the SDD failure mode is one giant task nobody can review. A useful heuristic: if a task can’t be tested in isolation, it’s too big.
Element 6 — Verification criteria
Specifically: what behaviour proves the work is done, what edge cases are handled, what error conditions are covered. The verification section is what distinguishes “done” from “looks done.” It’s also what an adversarial verifier agent (covered in Module 8) would check against.
In the spec, write verification as observable behaviour; the plan and tasks turn it into unit, integration, and end-to-end tests. For the to-do app’s “add a to-do”:
- Given an empty input, when the user presses Add, then no to-do is created
- Given a title with leading and trailing spaces, when it is added, then it is saved trimmed
- Given three existing to-dos, when a new one is added, then it appears at the top of the list
- After a page reload, every to-do and its done state are still there
- Edge case: a title longer than 200 characters is refused with an inline message
- Edge case: pressing Add twice in quick succession creates exactly one to-do
Notice that these are all things you can verify. “Should be performant” or “should handle errors gracefully” are not verification criteria; they are wishes.
2.What versus how: where each element lives
/speckit-specify writes the what and why — user-facing behaviour, goals, acceptance criteria — and leaves the tech stack out; its own quality checklist fails a spec that names languages, frameworks, or APIs. /speckit-plan takes the how: stack, architecture, technical constraints. The spec template has four top-level sections — User Scenarios & Testing, Requirements, and Success Criteria (all mandatory), plus Assumptions. Here is where each element lands:
| Element | Artifact | Where, exactly |
|---|---|---|
| 1. Outcomes | spec.md | User Scenarios & Testing: prioritized user stories (P1, P2…), each independently testable. Success Criteria: measurable, technology-agnostic outcomes. |
| 2. In / out of scope | spec.md | Requirements (FR-001…) for what’s in; Assumptions for what’s out this iteration. |
| 3. Constraints & assumptions | Split | Product-level → spec Assumptions. Technical → the plan’s Technical Context, or the constitution. |
| 4. Decisions already made | Split | Ones a user would notice → spec Requirements. Technical → the constitution or the plan. |
| 5. Task breakdown | tasks.md | Not in the spec. Generated by /speckit-tasks, one phase per user story. |
| 6. Verification | spec.md, then plan and tasks | User Scenarios & Testing: Given/When/Then acceptance scenarios and Edge Cases; Success Criteria. Test layers and tooling come later. |
When something is genuinely undecided, the spec says so with a [NEEDS CLARIFICATION: …] marker instead of guessing; /speckit-specify keeps at most three and asks you about each.
So Spec Kit doesn’t shrink the framework; it distributes it. A quick test for any line headed for spec.md: would a user or a product owner notice if this changed? If yes, it’s what. If only an engineer would notice, it’s how — it goes in the plan.
3.A worked example: from bad spec to good spec
Let’s take a deliberately weak spec and rewrite it.
Bad spec
Add file uploads
Users should be able to upload files. Make it secure and fast. Use AWS for storage.
This is vague enough that the agent has to guess most of what matters. It will probably build something. It will probably not be what you wanted. Let’s diagnose:
- Outcomes: “be able to upload files” — not observable. Upload how? Web form? CLI? API? Drag-and-drop?
- Scope: None. Image only? PDF only? Any file type? Size limits?
- Constraints: “Use AWS.” Which AWS service? S3? EFS? Lambda? (And that’s a how sitting in a what.)
- Decisions made: “secure and fast.” Neither is a decision; both are platitudes.
- Tasks: None.
- Verification: None. How would the team know it’s done?
Good draft (same feature, six elements applied)
Outcomes
- A signed-in user can attach a file to a project from the project detail page.
- The file appears in the project’s “Attachments” list within 2 seconds of upload.
- Other users with access to the project see the new attachment after a refresh.
- Files persist across deploys.
In scope
- Upload via drag-and-drop or file picker on the project detail page
- JPEG, PNG, and PDF only
- Max 10MB per file, max 100 files per project
- Display thumbnail (image) or filename + icon (PDF)
- Delete by uploader only
Out of scope
- Video uploads (separate Q3 feature)
- Inline preview / annotation (use existing native browser viewer)
- Sharing files outside the project
- Folder structures within a project
- Resumable uploads
Constraints
- Storage: S3 bucket
projects-attachments-prod(already provisioned)- Object key pattern:
<projectId>/<uuid>-<originalFilename>- Existing auth middleware enforces project membership; reuse it
- All uploads pass through the API server (no direct browser-to-S3 PUT)
Decisions already made
- File size enforced both client-side (UX) and server-side (security)
- File metadata stored in existing
attachmentstable (id, project_id, uploader_id, s3_key, filename, mime_type, size_bytes, created_at)- Use the existing
multermiddleware already in the codebase- Errors return HTTP 4xx with
{ error: string }, matching other endpointsVerification criteria
- Unit: File over 10MB rejected with HTTP 413
- Unit: Non-allowed MIME type rejected with HTTP 415
- Unit: Filename containing
../is sanitized before being stored as S3 key- Integration: Successful upload creates an
attachmentsrow and returns 201 with the row’s contents- Integration: GET /api/projects/:id/attachments returns the new file
- E2E: Drag-and-drop on the project page visually renders a thumbnail (image) or filename row (PDF) within 2 seconds
- Edge case: A user without project membership receives 403, no S3 write occurs
- Edge case: Network interruption mid-upload leaves no orphan rows in
attachments
This is roughly twice as long as the bad spec. It is also approximately 100 times more useful. The agent now knows exactly what to build, what not to build, what tools to use, and what tests to make pass.
A common worry at this stage: “isn’t writing this spec almost as much work as writing the code?” Sometimes yes — for short tasks. For non-trivial work, the spec is 20–40% of the time. The leverage is that the AI can now produce code that’s right the first time, and the spec persists as documentation that anyone can review.
Sorting the draft: spec or plan?
The draft answers all six questions, but it mixes what and how. Sort it before it goes near /speckit-specify. Outcomes, scope, and the behaviour behind each verification criterion become the spec, in the template’s shape (abridged):
## User Scenarios & Testing
### User Story 1 - Attach a file to a project (Priority: P1)
A project member adds a JPEG, PNG, or PDF from the project page by
drag-and-drop or file picker, and sees it under Attachments.
**Acceptance Scenarios**:
1. **Given** a member on the project page, **When** they drop a 2 MB PNG,
**Then** its thumbnail appears under Attachments within 2 seconds.
2. **Given** someone who is not a project member, **When** they try to
attach a file, **Then** it is refused and nothing is stored.
## Requirements
- **FR-001**: Members MUST be able to attach JPEG, PNG, and PDF files up to 10 MB.
- **FR-002**: The system MUST let only the uploader delete an attachment.
## Success Criteria
- **SC-001**: Attachments are still available after the application is redeployed.
## Assumptions
- Out of scope this iteration: video, inline preview or annotation, sharing
outside the project, folders, resumable uploads.
Everything an engineer chose — the bucket, the key pattern, the middleware, the table, the status codes — waits for the plan:
/speckit-plan Store files in the existing S3 bucket projects-attachments-prod,
keyed <projectId>/<uuid>-<originalFilename>. Uploads go through the API
server with the existing multer middleware. Record metadata in the existing
attachments table; reuse the membership middleware; enforce the size limit on
client and server. Errors are HTTP 4xx with { error: string }.
Nothing was lost. But now a product owner who has never heard of multer can review the spec, and the team can change storage providers without touching a single acceptance scenario.
4.Decomposition: keeping specs reviewable
The best-written spec in the world is useless if it’s too big to review. Two frameworks help with sizing.
INVEST
Each spec (or sliced sub-spec) should be:
- Independent — can be built without waiting on another spec
- Negotiable — a starting point for conversation, not a contract carved in stone
- Valuable — delivers user-visible or system-visible value on its own
- Estimable — small enough that you can roughly predict effort
- Small — completable in a few days or less
- Testable — has verification criteria you can actually run
If a spec fails any of these, slice it. The most common failures are small and testable — engineers tend to write specs that are genuinely too big or that conclude with “and then make sure it works” rather than concrete tests.
Spec Kit’s template applies the same thinking inside a single spec. Every user story gets a priority and must be independently testable: build only that story and you should still have something that delivers value. That matters downstream, because /speckit-tasks gives each story its own phase in priority order.
MoSCoW
Within a spec, prioritize requirements:
- Must have — without this, the feature doesn’t ship
- Should have — important but the feature ships without it if forced
- Could have — nice extras
- Won’t have — explicitly out of scope this iteration
MoSCoW is most useful when you’re tempted to write a giant in-scope list. Forcing yourself to mark some items “should” or “could” reveals the things that don’t actually need to be in this spec. Often they become a follow-up spec, or they become out-of-scope items.
In the template’s terms: the Must-haves are your P1 story; Should- and Could-haves become lower-priority stories or a follow-up spec; Won’t-haves go under Assumptions as explicit scope boundaries.
A practical rule
If your spec exceeds about 500 words of content (excluding boilerplate), it’s probably too big. Slice it. There are exceptions — security or compliance specs may legitimately need more — but treat exceptions skeptically. When an epic genuinely won’t fit, Spec Kit’s last-resort answer is a spec of specs: a roadmap of independently testable slices, each with its own spec that runs the full loop.
5.Constitution vs. spec: where context lives
Spec Kit keeps persistent project context — things true across all features, all specs, all PRs — in the constitution, a single file at .specify/memory/constitution.md. You write it once per project with /speckit-constitution (SPECTRA’s Guardrails agent, speckit.constitution) and revise it only when a principle genuinely changes. Other tools have the same idea: Kiro calls it steering; AGENTS.md files and memory banks play the same role. The spec captures task-specific context — what’s true only for this piece of work.
The constitution is also the yardstick every later artifact is checked against. /speckit-specify and /speckit-clarify read it before writing, the plan includes a constitution check that must pass before design work starts, and /speckit-analyze treats any conflict with it as critical. Workflow conventions belong here too — including your team’s spec-persistence choice from Module 1. That’s a team agreement, not a CLI setting, so record it where every agent will read it.
| Constitution | Per-feature spec |
|---|---|
| “Persistence is browser localStorage; no backend, no database” | “A to-do can carry an optional due date that survives a page reload” |
| “User input is validated before it is saved, with problems shown inline” | “An empty to-do title is refused with an inline message” |
| “Next.js App Router, React, TypeScript, and Tailwind; no second UI framework” | “Overdue to-dos are shown in red” |
| “All dates are stored as ISO 8601 strings” | (The constitution covers this; the spec doesn’t repeat it) |
Why this separation matters:
- Specs stay focused. A spec doesn’t have to repeat the conventions of the codebase every time. It just states what’s specific to this change.
- Conventions stay enforced. When you change the constitution (rare), every future spec and plan is checked against the new version. When you change a spec (often), other specs aren’t affected.
- Reviewability. A 200-word spec with an 800-word constitution is easier to review than a 1000-word spec.
A common adoption mistake: cramming constitution-level conventions into every spec, “just to be safe.” This produces the markdown-monster failure mode Böckeler warns about. Trust the constitution. If a convention isn’t in it but should be, fix the constitution.
6.Four common spec failures
Four patterns to watch for in your own writing and in review. Section 7 shows which gate catches each one.
Failure 1 — “How” leaks into “what”
The bad spec earlier in this module showed this in mild form (“Use AWS”). A more egregious version: function names, library names, and database column names appearing in the spec. These belong in the plan, not the spec. They constrain the agent unnecessarily and they entangle a description of intent with one particular implementation.
Cure: when you find yourself reaching for a code-shaped detail, ask “would a user or product owner notice if this changed?” If not, it’s how: move it to the plan, or to the constitution if it holds for every feature.
Failure 2 — Implicit assumptions
Specs that say “users can search” without saying what they’re searching, what fields are searched, what happens with no results, whether search is case-sensitive, whether typos are tolerated. The agent has to invent answers to all of these.
Cure: imagine you’re explaining the feature to a sharp but new engineer. Every question they’d ask is one your spec should answer — or record under Assumptions.
Failure 3 — Verification by vibe
“Should work correctly.” “Should be fast.” “Handles errors gracefully.” None of these are verifiable.
Cure: convert each vague criterion into a specific, testable statement. “Fast” becomes “search results appear within 1 second for a list of 500 to-dos.” “Errors gracefully” becomes “a save that fails leaves the list unchanged and tells the user what happened.”
Failure 4 — Specifying too much
The reverse of Failures 1–3: a spec that runs to 2000 words because the author wanted to be thorough. The agent and the reviewers both lose focus. The minor details overshadow the load-bearing ones.
Cure: keep the spec to what removes ambiguity. If a detail wouldn’t change the agent’s behaviour, it doesn’t belong in the spec. If it’s a project-wide convention, move it to the constitution.
The goal isn’t comprehensive — it’s just enough.
7.Checking a spec before you build on it
Specs have bugs too, and they’re cheapest to fix before a plan is built on them. Only /speckit-specify is strictly required before /speckit-plan; the checks below are optional quality gates (SPECTRA lists speckit.clarify and speckit.checklist as add-on agents). Use them whenever there is real ambiguity — for production work, most of the time.
7.1 /speckit-clarify: ask before you plan
Clarify scans the spec for gaps — unclear scope, missing error and empty states, unstated roles, vague adjectives — and asks at most five targeted questions per pass, one at a time, usually multiple-choice with a recommended answer. Each answer is written back into spec.md, logged under a dated Clarifications heading and applied to the section it affects, so the decision lives in the spec rather than a chat transcript.
Run it before /speckit-plan; designing on top of ambiguity is the rework it exists to prevent. It’s repeatable: run it again with a focus area to go after a different part of the spec.
/speckit-clarify Focus on who can see and delete attachments, and what happens when an upload fails partway.
7.2 checklists/requirements.md: the built-in self-check
/speckit-specify creates this file next to the spec and evaluates the spec against it: no implementation details; requirements testable and unambiguous; success criteria measurable and technology-agnostic; edge cases identified; scope clearly bounded; no [NEEDS CLARIFICATION] markers left. /speckit-clarify re-evaluates it after each pass.
The agent maintains this one, so treat its ticks as the agent’s own claim, not a sign-off — a fast way to see what’s still open.
7.3 Custom checklists: unit tests for requirements
/speckit-checklist generates a checklist for a focus area — checklists/ux.md, checklists/security.md — whose items test the spec, not the code: does it say something, clearly and consistently? In Spec Kit’s full path it runs after /speckit-plan and before /speckit-tasks.
/speckit-checklist Focus on upload limits, permissions, and failure handling.
| Tests the code (not a checklist item) | Tests the spec (a good checklist item) |
|---|---|
| A 12 MB upload shows an error | Is the behaviour for an over-limit file specified, including what the user is told? |
| Thumbnails render within 2 seconds | Does “within 2 seconds” say where the clock starts — on drop, or when the upload finishes? |
These checklists belong to the reviewer. The command leaves every item unchecked; a person ticks [x] only when satisfied the requirement is well written — [x] never means “built.” An agent may help evaluate items when you explicitly ask, but never approves them on its own. When an item fails, fix the spec with /speckit-clarify or /speckit-specify, not the checklist.
7.4 The gate at implement
Before it writes any code, /speckit-implement counts the checked and unchecked items in every file under checklists/. If anything is unchecked, it stops, shows you the counts, and asks whether to proceed anyway. It never ticks a box itself. An unreviewed checklist can’t slip through quietly — someone has to decide to go ahead.
7.5 Which gate catches which failure
| Failure | Caught by | How |
|---|---|---|
| 1. How leaks into what | checklists/requirements.md, confirmed by the reviewer | “No implementation details” is a built-in item; the reviewer moves each offending line to the plan. |
| 2. Implicit assumptions | /speckit-clarify | Its scan hunts for undefined scope, missing states, and unstated roles, and asks before the plan bakes a guess in. |
| 3. Verification by vibe | A custom checklist from /speckit-checklist | “Is ‘fast’ quantified?” is the kind of item it writes; the reviewer won’t tick it until the spec states a number. Clarify’s hunt for vague adjectives is an earlier net. |
| 4. Specifying too much | The human reviewer, backed by the constitution | No command flags a spec for being long. A person has to spot detail that doesn’t change behaviour and move project-wide conventions to the constitution. |
The pattern: agents draft, gates make gaps visible, people decide.
Writing exercise
You’re going to rewrite a deliberately bad spec into a good one. Allow yourself 25 minutes. Use the six-element framework.
Context
Imagine your team owns a customer-facing web app. The Customer Success team has asked engineering for a “comments” feature: customers should be able to leave comments on the items in their order history, mainly for their own future reference.
A junior engineer drafted this spec:
Add comments
Customers want to leave comments on their orders. We should add this. Make sure it’s secure and works on mobile. Save comments somewhere persistent. Allow editing and deleting. Should integrate with the existing order page. Use the database we already have.
Your task
Rewrite this as a proper spec using the six-element framework. Make reasonable assumptions where the original is vague — but write each assumption down in the appropriate section. You should produce something that:
- Has clear, observable outcomes
- States what’s in scope and what’s out of scope
- Lists constraints and assumptions
- Calls out any decisions already made (you can invent reasonable ones; just be explicit)
- Breaks the work into 4–8 tasks (
/speckit-taskswould regenerate these from the plan — here they prove the spec slices cleanly) - Has at least 6 verification criteria, including at least 2 edge cases
- Marks each line other than the tasks S (belongs in
spec.md) or P (belongs in the plan or the constitution)
Self-review checklist
After you finish, run your spec through this:
- Could a new engineer build the feature from your spec without asking the original requester anything?
- Does any line marked S dictate implementation (function names, library names, schema details, status codes)? If so, re-mark it P.
- Is each outcome observable from outside the system?
- Could you write each S verification criterion as a Given/When/Then scenario?
- Could you write at least one failing test for each verification criterion before any code exists?
- Is the S part under 500 words of actual content (excluding boilerplate)?
- Did you write down at least 3 out-of-scope items?
If you answered “no” to any of these, revise.
Yours doesn’t need to look exactly like this — assumptions can vary — but the structure should match.
Customer comments on order history items
Outcomes (S)
- On the order history page, a customer can add a free-text comment to any of their own past orders.
- The comment appears immediately under that order in the order history view.
- The customer can edit or delete their own comments.
- Comments persist across sessions and devices.
In scope (S)
- One comment per customer per order (a customer can edit, but not stack multiple)
- Plain text comments up to 500 characters
- Edit and delete actions, available only to the comment’s author
- Mobile-responsive UI matching the existing order history layout
Out of scope (S)
- Comments visible to anyone other than the comment’s author (no shared/public comments)
- Rich text or markdown formatting
- File attachments, images, or links with previews
- Notifications when a comment is added (no emails, no push)
- Customer Success team visibility in this iteration (separate spec)
- Comment threads or replies
Constraints
- (S) Usable down to a 375px-wide screen
- (P) Backend uses the existing Postgres database; no new infrastructure
- (P) Reuse the existing customer auth middleware
- (P) All endpoints follow the existing
/api/v1/<resource>patternDecisions already made (P)
- Comment is associated with the
(customer_id, order_id)pair (uniqueness constraint)- Soft deletes (
deleted_atcolumn), not hard deletes- Validation errors return HTTP 400 with
{ error: string }, matching existing endpoints- Comment timestamps stored as ISO 8601 UTC
Tasks (regenerated later by
/speckit-tasks)
- Add a
commentstable with the chosen columns and uniqueness constraint- Implement POST /api/v1/orders/:orderId/comment (create or replace own comment)
- Implement DELETE /api/v1/orders/:orderId/comment (soft delete own comment)
- Extend GET /api/v1/orders to include the customer’s own comment per order
- Add the comment UI to the order history page (display, edit-in-place, delete)
- Add mobile-responsive styles
- Write integration tests covering the verification criteria below
Verification (S as behaviour; the status codes are P)
- An empty comment is refused (HTTP 400)
- A comment over 500 characters is refused (HTTP 400)
- A customer cannot delete another customer’s comment (HTTP 403, nothing changes)
- A comment added to order X shows under order X only
- Editing a comment changes it in place; no second comment appears
- A deleted comment no longer appears anywhere
- On a 375px-wide screen, the comment input and the order details are both visible without horizontal scrolling
- Edge case: a rapid double-submit of the comment form creates one comment, not two
- Edge case: an order that doesn’t belong to the customer behaves as if it doesn’t exist (HTTP 404, not 403, to avoid leaking that it does)
Notice where things landed. The spec keeps outcomes, scope, one product-level constraint (the phone-width screen), and the behaviour behind each check. The database, middleware, endpoint pattern, soft deletes, uniqueness key, error format, and status codes are plan material — or constitution material, if they hold for every feature. And notice what it doesn’t include at all:
- No SQL DDL — that goes in the plan
- No mention of specific frameworks or libraries — the constitution already records them
- No copy text for buttons or error messages — design and copy own that
- No timing estimates — those are sprint-planning concerns, not spec concerns
If you compare this to your version, focus on the structure and completeness of each element, and on whether your S/P split matches, not on getting the exact same wording.
What’s next
In Module 3, the greenfield lab, you’ll install SPECTRA and take a small to-do app through the loop yourself — constitution, spec, plan, tasks, implement — reviewing each artifact at its gate. The goal is to feel the workflow in your hands before Module 4 applies it to an existing codebase.
Bring this module’s writing exercise. The six elements are what /speckit-specify needs from you, and knowing which half belongs to /speckit-plan will keep your first spec clean.