Learning objectives
By the end of this module, you will be able to:
- Install SPECTRA into a new project and confirm your AI agent can see the Spec Kit and SPECTRA commands.
- Run Spec Kit’s full path end to end on a small greenfield app:
/speckit-constitution→/speckit-specify→/speckit-clarify→/speckit-plan→/speckit-checklist→/speckit-tasks→/speckit-analyze→/speckit-implement→/speckit-converge. - Name the artifact each step produces and review it critically before moving on.
- Act at each human gate: answer clarify’s questions, tick the checklist yourself, and fix each analyze finding where it belongs.
- Recognize when the agent is making assumptions you should have specified explicitly.
What you'll build
A simple single-page to-do web app. Users can add tasks, see them listed, mark them done (and undo), and delete them. Tasks persist in the browser via localStorage — no database, no backend.
Tech stack, as create-next-app 15 scaffolds it:
- Next.js 15 (App Router) for the framework
- React 19 with TypeScript
- Tailwind CSS v4 for styling
- localStorage for persistence
This is small enough to finish in two hours, but real enough to require thinking about edge cases. It's also a mirror for Module 4, whose starter is a to-do app of the same shape on the same framework (it pins React 18 and Tailwind CSS 3; nothing in either lab depends on the difference).
The route
This lab runs Spec Kit’s full path: the core loop plus three optional quality gates — clarify, checklist, and analyze — which SPECTRA’s roster lists as add-ons. A feature this small could take the short path (specify → plan → tasks → implement → converge); you take the long way once so you know what each gate buys you.
Agents draft, people decide. Every step stops at a human gate, and in this lab every role at the gate is you. Feature artifacts land in specs/001-<name>/.
| Step | You run | It produces | Human gate |
|---|---|---|---|
| 2 | /speckit-constitution | .specify/memory/constitution.md | Foundation — leads approve every standard |
| 3 | /speckit-specify | spec.md, checklists/requirements.md | Plan — the product owner approves intent and scope |
| 4 | /speckit-clarify | Your answers, written into spec.md | Plan — the product owner answers |
| 5 | /speckit-plan | plan.md and supporting design files | Design — architects approve the design |
| 6 | /speckit-checklist | checklists/<name>.md | Plan, revisited — the reviewer ticks each item |
| 7 | /speckit-tasks | tasks.md | Implement — engineers review the breakdown |
| 8 | /speckit-analyze | A report; no file changes | Implement — you decide what each finding means |
| 9 | /speckit-implement | Code; tasks ticked [X] | Implement — engineers review every change |
| 10 | /speckit-converge | Nothing, or new tasks in tasks.md | Implement — you decide when it’s done |
| — | /speckit-spectra-create-pr (offered) | Nothing: you decline it | Deploy — a maintainer merges |
speckit.plan command belongs to the Design phase: it writes the technical plan..specify/feature.json, not by the branch you have checked out. create-next-app normally runs git init and makes one commit for you (--disable-git skips that); after that, this lab never asks you to commit. In real work, committing at each human gate is a cheap habit (Module 8). For numbered feature branches such as 001-todo-app, specify extension add git adds them — the active feature still comes from .specify/feature.json.1.Setup (15 min)
1.1 Pick your AI agent
SPECTRA works with any coding agent Spec Kit supports — Claude Code, GitHub Copilot, Cursor, Gemini CLI, and many more. The course’s command examples use the Claude Code and Copilot trigger form; if your agent spells commands differently, see Module 1’s “Command spelling” note. If your team has mixed adoption, pair up: one person drives, one observes.
1.2 Scaffold the Next.js project
From a directory of your choice:
npx create-next-app@15 todo-app --typescript --tailwind --app --no-src-dir --no-eslint --turbopack --import-alias "@/*"
cd todo-app
The flags pre-answer the prompts (TypeScript, Tailwind, App Router, no src/, no linter, Turbopack, default import alias). If your version still asks something, accept the default. Then run npm run dev, open http://localhost:3000, confirm you see the Next.js welcome page, and stop the server with Ctrl+C.
1.3 Install SPECTRA
SPECTRA ships as a uv tool. Install it once, from anywhere:
uv tool install spectra-cli --from git+https://github.com/telus-digital/spectra
Run spectra on its own to verify: the banner’s cli vX.Y.Z line is your installed version. Bare spectra is informational only and never touches the current folder. (No uv or Git yet? The SPECTRA install guide has per-OS steps.)
spectra is a setup and lifecycle command, not a replacement for Spec Kit. The workflow you’re about to run is Spec Kit’s; SPECTRA puts it in place, keeps it current, and adds its own speckit.spectra.* agents on top.
1.4 Install SPECTRA into the project
From todo-app/:
spectra install
That one command:
- Installs Spec Kit’s
specifyCLI if it’s missing. - Offers to initialize this folder as a Spec Kit project. Say yes: it runs exactly
specify init --here --force— “here” is this folder, and--forcelets it proceed in a folder that already has files. It may overwrite Spec Kit’s own managed files but doesn’t delete your app. When it asks for your coding agent, pick the one from 1.1. - Registers the public SPECTRA catalog.
- Installs the SPECTRA extension.
Your project now has, alongside the scaffold (shown for Claude Code):
.specify/
memory/constitution.md # the constitution - a template until step 2
templates/ # spec, plan, tasks, checklist, constitution templates
extensions/spectra/ # the SPECTRA extension
.claude/skills/ # speckit-* and speckit-spectra-* skills
specify init infers nothing from your code; everything under .specify/ starts as a template.
Then check the stack and see what’s on offer:
spectra version
spectra agent-list
spectra version reports every part of the stack. This course needs Spec Kit 1.0.9 or later; if yours is older, spectra update brings it current. spectra agent-list prints SPECTRA’s roster by SDLC phase, marking each agent core or add-on and saying whether Spec Kit or SPECTRA provides it. Today you use Spec Kit’s agents; the speckit.spectra.* ones are beyond this lab.
uv tool install specify-cli, then run specify init --here --force --integration claude in todo-app/ (specify integration list shows the other agents’ keys). Add --non-interactive for CI or agent harnesses, and --script sh|ps|py to pick the helper-script flavour.1.5 Sanity-check the agent
Open your agent in todo-app/ and type /speckit. The command list should show speckit-constitution through speckit-converge, plus SPECTRA’s speckit-spectra-* agents. If not, restart the agent and check it’s running in todo-app/. (Don’t test with a bare /speckit-specify: without a description it just stops with an error.)
2.Write the constitution (10 min)
The constitution holds project-wide standards that don't belong in any single spec. SPECTRA calls the agent that writes it Guardrails. It lives at .specify/memory/constitution.md and starts as a template. Give your standards to the command:
/speckit-constitution Record these standards for a single-page to-do app.
Stack
- Next.js 15 (App Router) with TypeScript; React 19 as scaffolded
- Tailwind CSS v4 for styling
- localStorage for persistence — no backend, no database, no API routes
Code organisation
- The page lives in app/page.tsx
- Components live in app/components/
- Storage helpers and shared types live in lib/storage.ts
- Components that use browser APIs or React state declare "use client"
Styling
- Tailwind utility classes only; no separate CSS files for layout
- app/globals.css keeps what the scaffold put there; add no new rules
Data
- A todo is { id: string, text: string, completed: boolean, createdAt: string }
- createdAt is an ISO 8601 string
- IDs come from crypto.randomUUID() (collision-safe, in all modern browsers)
- The localStorage key is one named constant in lib/storage.ts, never a
repeated magic string
UI
- Single page, no routing
- An empty state when there are no tasks
- Newest task at the top of the list
- Completed tasks show a strikethrough; the row is not removed
Workflow
- Specs are spec-first: written before the code, not maintained afterwards
- No automated test suite in this lab; each user story is verified by hand
against its acceptance scenarios
The agent maps your list onto the constitution template — named principles in MUST/SHOULD language, a version number, a governance section, and a Sync Impact Report comment at the top — and writes .specify/memory/constitution.md. (You can edit that file by hand instead; the command adds the structure and keeps dependent templates in step.)
2.1 Review it
- Every standard you gave it is there, and nothing has been invented. Invented standards turn into noise in every later plan and analysis.
- The rules you mean as non-negotiable read as MUST: the ID generator, the single storage-key constant, no backend.
- No
[PLACEHOLDER]tokens are left. A ratification date marked TODO is fine for a lab.
This is short on purpose. The constitution should hold durable conventions, not the world. If something here turns out to be wrong later, you'll change it once and every future spec inherits the change.
crypto.randomUUID() and a single named storage-key constant are decisions worth pinning at the project level so the agent doesn't reinvent them in every spec. The Module 4 starter follows neither, and you'll see there why that matters. The Workflow lines settle two things the agent would otherwise guess: how long the spec matters (spec-first, from Module 1) and whether to set up a test framework.3./speckit-specify — the what and why (10 min)
/speckit-specify Build a single-page to-do app for one person keeping a short
personal list in their own browser. They can add a task, see all their
tasks in one list with the newest at the top, mark a task as done (and
undo that), and delete a task. Their tasks are still there after they
reload the page or come back later in the same browser. There are no
accounts, and nothing leaves the browser.
Notice what’s missing: Next.js, React, Tailwind, localStorage. specify is for the what and the why. The stack is already in the constitution, and the design belongs to /speckit-plan.
The agent creates a feature directory (for example specs/001-todo-app/), writes spec.md, and records the directory in .specify/feature.json as the active feature. It also creates checklists/requirements.md, a built-in spec-quality checklist whose items specify and clarify tick and untick themselves as the spec changes — read those ticks as the agent’s own claim, not a sign-off. If it hit a decision it couldn’t make, it may ask you up to three questions straight away. Answer them; the dialogue is part of the practice.
3.1 Review checklist
Don't accept the draft as-is. It has prioritised user stories with Given/When/Then acceptance scenarios, edge cases, numbered requirements (FR-001…), success criteria, and assumptions. Check it against the six-element framework from Module 2:
- Outcomes are observable (someone can tell whether the work is done by using the app)
- In-scope items are listed
- Out-of-scope items are listed (this is the one most often missing)
- Constraints are stated (or covered by the constitution and not repeated here)
- Decisions made — some will still be open; the next step is for those
- Verification criteria — the acceptance scenarios are concrete, runnable checks, not vibes
If any are weak, edit the spec directly or ask the agent: “The out-of-scope list is missing — please add at least four items based on what the constitution and the request imply.” If the draft names components or storage APIs, the how is leaking into the what; trim it.
/speckit-specify run starts a new feature directory (002-…) and makes it the active one. Refine this spec by editing it, by asking in chat, or with clarify next.4./speckit-clarify — settle the open questions (10 min)
/speckit-clarify
Clarify scans the spec for gaps that would change what gets built and asks about the ones that matter most — at most five questions per pass, one at a time, each with a recommended answer and its reasoning. Reply with an option letter, “yes” to take the recommendation, or a short answer of your own. After each answer it writes the decision into spec.md: a Q → A line under a ## Clarifications heading, plus the change itself in the section it affects.
4.1 Decide before it asks
A thin to-do spec leaves these open. Have an answer ready for each; clarify will probably ask about some, and you should raise the rest.
- Empty input. An empty string? Only whitespace? Reject silently, show an error, disable the button?
- Completed tasks. Stay in place, sink, or hide? (Your constitution says they stay; if asked, answer consistently.)
- Editing existing tasks. Recommend out of scope for this lab; it makes a good follow-up feature.
- Maximum length. A character limit on task text?
- Confirmation on delete. Recommend hard delete, no confirmation.
- localStorage failures. If the browser is in private mode and writes throw: crash, ignore silently, or tell the user?
If something is still open after one pass, run it again with a focus:
/speckit-clarify Focus on what the user sees when saving fails, and on very long task text.
- Empty or whitespace-only input: nothing is added and no error is shown; text is trimmed before saving.
- Completed tasks: stay where they are, struck through.
- Editing: out of scope.
- Length: 200 characters at most; the input accepts no more.
- Delete: immediate, no confirmation.
- Saving fails: the app keeps working for the rest of the visit and shows a short, non-blocking message that changes won’t be kept.
Yours can differ. What matters is that each is now a decision in the spec, not a guess in the code.
4.2 Check the answers landed
spec.mdhas a## Clarificationssection with one Q → A line per answer- Each answer also changed the section it affects — the empty-input rule is a requirement or an edge case, not only a line under Clarifications
- No earlier sentence still contradicts an answer
You stop iterating on the spec when a new engineer could implement the app from your spec without asking you anything. Not before.
5./speckit-plan — the how (15 min)
/speckit-plan Build it on the stack the constitution sets out. Keep it small:
one page, three components, one storage module.
This is where implementation detail belongs. The agent writes plan.md — technical context, a Constitution Check against your standards, the project structure — plus supporting files beside it: research.md (decisions and why), data-model.md (the Todo entity), and quickstart.md (how to run and validate).
5.1 Review checklist for the plan
The plan should:
- Identify the components to create — minimum: a form, a list, and a list-item component
- State where state lives (the page, lifted up; not scattered across components)
- Describe the localStorage read/write pattern (load once on mount; save on change; handle the SSR case where
windowis undefined) - Decide which fields exist on a Todo object and where the type is defined
- Pass its Constitution Check honestly. A plan that “passes” while using
Date.now()for IDs hasn't checked anything.
5.2 What the plan should not contain
- Full component bodies (that's
/speckit-implement's job) - Specifics that contradict the constitution (if it does, fix one or the other — both being authoritative is the point of having both)
- Things that should have been in the spec (“we should also support tags” — no, that's a scope change; take it back to the spec)
If the plan is wrong, fix it before moving on. The cost of a wrong plan caught here is minutes. The cost of a wrong plan caught at /speckit-implement is potentially the whole afternoon.
5.3 SSR / hydration: the one gotcha to watch for
Next.js renders pages on the server first, then hydrates them in the browser. localStorage doesn't exist on the server. If the plan reads localStorage during the initial render, the client and server will produce different HTML and React will throw a hydration warning.
The right pattern: the page renders an empty initial state on first paint, then a useEffect hook reads localStorage after mount and updates state. The plan should call this out explicitly. If it doesn't, push back: “How does this avoid hydration mismatch when localStorage is read?”
This is the kind of stack-specific issue the constitution can't anticipate but the plan must.
6./speckit-checklist — unit tests for your requirements (10 min)
/speckit-checklist Focus on user-facing behaviour: empty states, input rules, and what happens when saving fails.
This checklist tests the spec, not the code: is each requirement complete, clear, consistent, measurable? The agent may ask up to three quick questions first, then writes checklists/<name>.md (ux.md, say) with every item unchecked. Something like:
- [ ] CHK001 Is the behaviour for whitespace-only input specified? [Edge Case, Spec §FR-003]
- [ ] CHK002 Is "newest at the top" defined for tasks added in the same second? [Clarity]
- [ ] CHK003 Is what the user sees when saving fails described? [Gap]
6.1 Review and tick — yourself
Work through the file with spec.md open beside it:
- If the spec answers the question, change
- [ ]to- [x]. The tick means you are satisfied with the requirement — not that anything is built. - If it doesn’t, fix the spec first (edit
spec.md, or/speckit-clarifywith that item as the focus), then tick. - If an item asks about something you’ve deliberately left out, make sure the out-of-scope list says so; then it’s settled and you can tick it.
The agent never self-approves. You can ask it to help evaluate an item (“does the spec answer CHK003?”), but the tick is yours. Leave anything unticked and /speckit-implement will stop before it starts and ask whether to proceed anyway.
checklists/requirements.md is the built-in one: specify and clarify tick and untick its items themselves as the spec changes. Treat those ticks as the agent’s claim, not a sign-off, and challenge any you disagree with. The checklists /speckit-checklist generates are reviewer-owned: the command leaves every item unchecked, and only you tick them. Implement counts both.7./speckit-tasks — break it down (5 min)
/speckit-tasks
The agent turns the plan into tasks.md: small, ordered tasks, each naming the file it touches, in phases — Setup (housekeeping, such as clearing the scaffold’s demo page), Foundational (what every story needs first: the Todo type, the storage key, load and save helpers), one phase per user story in priority order, and Polish (cross-cutting clean-up and final verification). Tests, when the spec asks for them, sit inside each story’s phase.
[P] marks a task that can run in parallel with its neighbours — different files, no dependency on unfinished work. [US1], [US2]… tag the story a task serves. During implement, finished tasks are ticked [X]. An excerpt might look like:
## Phase 3: User Story 1 - Add and see tasks (Priority: P1)
- [ ] T004 [P] [US1] Create the add-task form in app/components/TodoForm.tsx
- [ ] T005 [P] [US1] Create the list and row components in app/components/
- [ ] T006 [US1] Hold state in app/page.tsx; load after mount, save on change
7.1 Review checklist
- Tasks are roughly the right size — neither “build the app” (too big) nor “import useState” (too small)
- Tasks are ordered so dependencies resolve naturally (storage helpers and types before components; form before list; list before delete)
- Each task has a clear “done” criterion you could check off without ambiguity
- The hydration handling is its own task or explicitly part of the page-component task
[P]appears only on tasks that really touch different files
7.2 Common defects
- Mega-task syndrome — “Build the page” with no breakdown. Push back: split into state setup, render, mount-effect for load, change-effect for save.
- Missing wiring — components listed but no task to connect them on the page. Add it.
- No verification step — your constitution says stories are verified by hand, so Polish should end with “verify every acceptance scenario in
spec.md”. If it's missing, add it.
8./speckit-analyze — catch drift before you build (10 min)
/speckit-analyze
Analyze reads the spec, plan, tasks, and constitution together and reports where they disagree: a requirement with no task, a task with no requirement, a plan choice that contradicts the spec, vague wording, one thing called two names. It is read-only — it never edits a file. You get findings graded CRITICAL, HIGH, MEDIUM, or LOW, a table mapping each requirement to its tasks, and an offer to suggest fixes it won’t apply on its own. Any conflict with the constitution is automatically CRITICAL.
8.1 Fix each finding in the step that owns it
| The finding is about… | Fix it in… |
|---|---|
| A requirement — missing, vague, or contradictory | The spec: /speckit-clarify, or edit spec.md |
| The design — a plan choice that breaks the spec or the constitution | The plan: /speckit-plan, or edit plan.md |
| The task list — a gap, an orphan task, a wrong order | The tasks: re-run /speckit-tasks, or edit tasks.md |
Patching tasks.md to cover a requirement problem just hides the disagreement. Fix the source and let the fix ripple (a changed requirement may mean re-running /speckit-plan or /speckit-tasks), then re-run /speckit-analyze. Repeat until it comes back clean: nothing CRITICAL, and any MEDIUM or LOW you leave is a call you made, not one you skipped.
- The empty-state requirement has no task. Owner: the task list.
- The plan generates IDs with
Date.now(). A constitution conflict, so CRITICAL. Owner: the plan; regenerate the tasks after. - “Newest at the top” in the spec, “sorted by date” in the plan. Terminology drift. Owner: the plan.
- The 200-character limit from clarify has no task. Owner: the task list.
Illustrative only. If your first run is clean, read the coverage table anyway.
9./speckit-implement — build it in stages (20 min)
Before it writes a line, implement counts the boxes in every checklist under checklists/. If any are unticked, it shows a table and asks whether to proceed anyway. The honest answer is usually “no” — go back to step 6.
9.1 Scope each run
Don’t let it build everything in one go. Scoped runs are easier to review, and on large features they keep the agent inside its context window. Tell it where to stop:
/speckit-implement only execute the Setup and Foundational phases, then stop and report progress
Check the app still runs and the storage module follows the constitution. Then:
/speckit-implement only execute the User Story 1 phase, then stop and report progress
Continue one story at a time, then Polish. Task ranges work too (only execute tasks T001-T006). Finished tasks are ticked [X], so each run picks up where the last stopped. Verify each stage before you start the next.
9.2 Watch for these moments
- The agent invents a new requirement. If it suddenly adds a “due date” field that wasn't in the spec, stop it. Either the spec was wrong (go back and fix it) or the agent is hallucinating scope. (If you find yourself wanting due dates, don't add them here — that's the Module 4 brownfield exercise.)
- The agent uses
Date.now()for IDs. The constitution specifiescrypto.randomUUID(). Push back. This is exactly the kind of small constitution violation that becomes cruft over time if uncaught. - The agent hardcodes the localStorage key. Same logic — the constitution specifies a single named constant. If the agent inlines
"todos"strings, push back. - The agent skips the hydration consideration. If you see localStorage being read in a component body (not inside a
useEffect), the browser will warn. Have the agent fix it.
9.3 The pull-request offer — decline it
After every implement run, SPECTRA’s after_implement hook offers /speckit-spectra-create-pr (“Open a pull request for this spec?”). Decline it here. Declining does nothing: nothing is checked, committed, or pushed. Accepting wouldn’t get far anyway — the command needs the gh CLI signed in and a GitHub remote, and this repository has none.
On a real project you’d accept once the feature is done — after converge reports Converged — with the repository on GitHub and the work on a feature branch. It still asks before every commit, push, and the pull request itself. That’s the Deploy gate: the agent opens the pull request; a maintainer decides whether it merges. You can always run /speckit-spectra-create-pr yourself later.
9.4 Run the app
Once the last phase is done, run npm run dev, open http://localhost:3000, and try:
- Add a task. Does it appear at the top of the list?
- Try to add an empty or whitespace-only task. Does the app do what you decided in step 4?
- Mark a task done, then undone. Does the strikethrough appear and disappear?
- Delete everything. Do you see the empty state?
- Add three tasks, refresh the page. Are all three still there?
- Open the browser devtools → Application → Local Storage. Is there a key matching the constant from your constitution? Does its value look like a JSON array of todo objects?
If any of these fail, you have a divergence between spec and code. Is the spec wrong (you didn’t specify what you actually wanted), or the code (the agent missed something the spec stated)? Whichever is wrong, fix that one. Then re-verify.
10./speckit-converge — close the gap (5 min)
/speckit-converge
Run it once implement has worked through the current tasks.md. Converge compares the code with the spec, plan, tasks, and constitution, and summarises each gap as missing, partial, contradicts, or unrequested (code nobody asked for). Then it ends one of two ways:
- Converged. No gaps;
tasks.mdis left exactly as it was and you get a success message. You’re done. - Tasks appended. It adds a Convergence phase to the end of
tasks.md, one task per gap, each tracing to its source — for example- [ ] T019 Show the empty-state message per FR-006 (missing).
Converge is append-only: it leaves your code alone, never removing a line, and never touches the spec or plan. Even unrequested code gets a task to review it, not a deletion.
Read appended tasks before you implement them. If one traces to a requirement you no longer want, that’s a change to the spec, not a task to quietly skip. Then implement (decline the pull-request offer again) and converge again. Each pass should find less. When it says Converged, run the checks in 9.4 one last time.
11.Reflection (10 min)
Spend 10 minutes writing answers to these in a REFLECTION.md file in your project root. You don't need to share these with anyone, but writing them down is the difference between learning the practice and just executing the steps.
- Where did clarify ask about something you'd have left implicit — and what would the agent have assumed?
- What got caught at
/speckit-planreview that would have been more painful to fix at/speckit-implement? (The hydration handling is the obvious candidate — was there anything else?) - Which checklist items couldn't you tick honestly on the first read? What did you change?
- What did analyze find, and which step owned each fix?
- Did converge append anything? Did the agent invent scope anywhere, and how did you notice?
- Of the conventions in your constitution, which did the agent honor without prompting, and which did you have to reinforce?
- Which quality gates would you keep for a feature this size, and which for a production one? Overall, how does this compare to “just write a prompt and let the agent code”?
There's no right answer to any of these. The honest one is the useful one.
12.Common issues and how to handle them
“The agent's spec is way too long”
Edit it down. Spec Kit's default templates can be verbose, and some agents pad them further. The test from Module 2 still applies: if a sentence wouldn't change the agent's behavior, it doesn't belong. Stack details that leaked in from the constitution can go too — the plan picks them up anyway.
“The agent ignored my constitution”
Analyze and converge both treat a constitution conflict as their most severe finding, so these usually surface. If the agent still uses Date.now() despite the constitution, reference the rule explicitly in the plan (“Per the constitution, IDs use crypto.randomUUID()”) or re-prompt mid-implement. If your agent consistently ignores the constitution, that's a tooling-level concern worth raising on your team.
“The steps blur into each other”
Some agents will helpfully (or annoyingly) run several steps in one pass when a request is specific enough. Run the commands one at a time and review the artifact between each. The whole point of the workflow is the human gates.
“Clarify asked nothing”
It found no gaps it judged high-impact. If you know of an open question, name the area: /speckit-clarify Focus on delete behaviour and text length. Or write the decision into spec.md yourself.
“Implement stopped to ask about unchecked items” / “The agent ticked my checklist”
The stop is working as designed: finish the review in step 6 rather than answering “yes” out of habit. Ticks in checklists/requirements.md are expected — specify and clarify maintain them — but they’re the agent’s claim, so check them. Ticks in a checklist from /speckit-checklist should only ever be yours; untick anything you haven’t reviewed.
“The commands are working on the wrong feature”
You probably ran /speckit-specify twice, and the newer directory is now active. Open .specify/feature.json; it should read like {"feature_directory": "specs/001-todo-app"}. Point it back, or set the SPECIFY_FEATURE_DIRECTORY environment variable. Checking out a Git branch does not change the active feature.
“Converge keeps appending tasks”
Each pass should find less. If the same gap keeps coming back, the spec and the code disagree about something another implement pass can’t settle. Decide which one is right, and fix that one.
“I want to skip the quality gates”
You can. Only /speckit-specify is strictly required before /speckit-plan; clarify, checklist, and analyze earn their keep wherever there’s real ambiguity. For this lab, run them all. After the lab, decide for your team.
“The hydration warning won't go away”
The classic causes:
- localStorage being read during render rather than inside a
useEffect. - The initial state of
useStatediffering between server and client. - A component that uses
Date.now()orMath.random()during render (different value on server vs client).
The fix in all three cases is the same: render a stable initial state on the server, then update once mounted. The plan should have called this out — if it didn't, that's a useful note for your reflection.
What you should now know
- Spec Kit’s full path produces a reviewable artifact at every step, and every step has a human gate.
- The constitution holds durable conventions; the spec holds this feature’s intent. Keeping them separate keeps both readable.
- Each step forces a different decision: what (specify), what exactly (clarify), how (plan), is the spec good enough (checklist), in what order (tasks), do they agree (analyze), code (implement), is it done (converge).
- The quality gates never approve themselves: you answer clarify, you tick the checklist, you decide what each analyze finding means.
- Stack-specific gotchas (like Next.js hydration) belong in the plan, not the constitution.
What's next
In Module 4 you'll take the same workflow into a brownfield codebase — the starter to-do app shipped with this course — and add a due date to it. The loop is the same; what changes is where the context comes from. Instead of writing standards before any code exists, you draw guardrails from code that already does, and you keep the first spec to one bounded change. It's the centerpiece of the course, and where most teams find SDD hardest.