speckit.plan: From Functional Spec to Go Technical Plan
Complete guide to speckit.plan for turning a functional Golang spec into a technical implementation plan. How to read plan.md, validate its quality, review the generated SQL, and modify it before implementation begins.
speckit.plan: From Functional Spec to Technical Go Plan
speckit plan is the bridge between “what users need” and “how to build it” — the command that drives your speckit plan golang technical implementation step. It transforms a clean, tech-free spec.md into an architecture-rich plan.md: file structure, SQL schema, API design, and implementation order.
This article covers the anatomy of the generated plan.md, how to validate its quality, how to review the SQL it produces, and how to modify it before implementation starts.
08.1 Running specify plan
The command takes the feature name and reads everything the earlier stages produced. The snippet below runs the plan pass on product-search.
1specify plan product-searchSpec Kit reads constitution.md, spec.md (updated after clarify), clarifications.md, and the existing code under internal/ for pattern consistency, then writes .specify/features/product-search/plan.md. The takeaway: the plan is not invented in a vacuum — it is grounded in your rules, your clarified requirements, and the patterns already in your codebase.
08.2 Key Sections of plan.md
A generated plan is not a loose sketch; it has a fixed structure you can review section by section. The ten sections below are what every plan.md contains:
- Architecture Diagram — Mermaid class diagram showing layer relationships
- File Structure — the exact files to CREATE and MODIFY
- Database Schema Changes — migration SQL with a rollback plan
- New Types and Structs — Go type definitions
- Repository Implementation Plan — SQL queries
- API Design — endpoint, parameters, success and error responses
- Implementation Order — phase-by-phase sequence
- Test Plan — test function names mapped to ACs
- Risk Assessment — known risks with mitigations
- Dependencies and Assumptions — what the plan assumes
Knowing this fixed shape makes review mechanical: you can check each section against the spec instead of reading a wall of prose looking for gaps.
08.3 Plan Validation
Before trusting a plan, run its built-in validator. The command below checks the plan against the spec and the constitution.
1specify plan product-search --validate
2
3# ✅ All spec ACs accounted for in test plan
4# ✅ All error cases have error_code mappings
5# ✅ Database schema consistent with constitution (uuid, timestamptz)
6# ⚠️ Risk 2 has no concrete mitigation
7# ✅ Implementation order respects layer dependencies
8# ✅ No ORM references (constitution compliant)The validator catches the mechanical failures — an AC with no test, an error case with no code, a risk with no mitigation. Follow it with a manual checklist: architecture compliance → completeness → type consistency → SQL review → risk assessment. Automation clears the obvious; your eyes clear the rest.
08.4 SQL Review: What to Check
The single riskiest output of a plan is its SQL, because valid SQL is not the same as fast SQL. The command below confirms whether the planned index is actually used.
1-- Check: Is the GIN index actually used?
2EXPLAIN ANALYZE
3SELECT ... FROM products WHERE
4 to_tsvector('indonesian', name || ' ' || COALESCE(description, ''))
5 @@ plainto_tsquery('indonesian', $1)
6
7-- Look for: "Bitmap Heap Scan using idx_products_fts"
8-- Red flag: "Seq Scan" means the index isn't being usedThe rule is simple: always run EXPLAIN ANALYZE locally before committing the plan. A Seq Scan in the output means the AI’s query looks correct but will crawl on a real table — exactly the kind of issue that never shows up until production traffic hits it.
08.5 Modifying plan.md
The generated plan is a draft, not a verdict — you can regenerate it with extra instructions or edit it directly. The commands below show both paths.
1# Regenerate with additional instructions
2specify plan product-search --add-instruction "Include Redis cache as Phase 5"
3
4# Edit directly for minor changes
5vim .specify/features/product-search/plan.md
6
7# Validate after changes
8specify plan product-search --validateWhichever route you take, re-run --validate afterward. Editing a plan by hand is fine for minor tweaks, but the validator ensures your change didn’t quietly break the AC-to-test mapping or the layer ordering.
08.6 Plan for Schema Migrations
When a plan touches an existing table, the migration strategy matters as much as the schema itself. The section below shows a zero-downtime migration with verification and rollback.
1## Schema Migration Strategy
2
3### Migration: Zero-downtime (CONCURRENTLY)
4CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_products_fts
5ON products USING gin(to_tsvector('indonesian', name || ' ' || COALESCE(description, '')));
6
7### Verification before deployment
8SELECT indexname FROM pg_indexes
9WHERE tablename = 'products' AND indexname = 'idx_products_fts';
10-- Must return 1 row before deploying code
11
12### Rollback
13DROP INDEX CONCURRENTLY IF EXISTS idx_products_fts;The pattern to internalize is the three-step safety net: build the index CONCURRENTLY so it never locks the live table, verify it exists before shipping code that depends on it, and keep a rollback ready. A good plan always includes the way back out.
08.7 Plan Complexity Indicator
Every plan ships with a complexity estimate you can feed into sprint planning. The block below shows a typical indicator.
1Estimated complexity: Medium
2Files: 8 new + 3 modified + 1 migration
3Test cases: 12
4LOC estimate: ~450 lines
5Time estimate: 3-4 developer days
6Risk items: 3 (1 high, 2 medium)Treat this as an input, not a commitment — it is an AI estimate, not a guarantee. It is useful for rough sizing during sprint planning, but the actual budget should carry a buffer for the unknowns the AI cannot see.
08.8 Test Plan Mapping to ACs
A strong plan proves completeness by mapping every acceptance criterion to a named test. The mapping below shows the 1:1 relationship.
1TestSearchProducts_ValidKeyword_ReturnsResults → AC1, AC3
2TestSearchProducts_DeactivatedProduct_NotInResults → AC2
3TestSearchProducts_OutOfStockProduct_ShowsBadge → AC2a (from clarify Q1)
4TestSearchProducts_WithCategoryFilter → AC4
5TestSearchProducts_NoResults_ReturnsEmpty → AC6
6TestSearchProducts_ShortKeyword_ValidationError → AC7Because each AC points to a specific test, spec-compliance verification becomes mechanical rather than subjective — you can literally count that no acceptance criterion is left untested before you approve the plan.
08.9 Comparing Plan Against Existing Patterns
Before implementing, confirm the plan matches the conventions already in your repository. The commands below diff the plan against the existing repository code.
1# See the existing repository pattern
2cat internal/product/repository/postgres_repository.go
3
4# Compare function signatures in the plan
5cat .specify/features/product-search/plan.md | grep "func "
6
7# Verify: function signatures, error types, return types, package structureThe goal is consistency: if the plan invents a signature or error type that differs from your established pattern, fix it now — reconciling it after the tasks are generated means regenerating everything downstream.
08.10 Plan as Sprint Planning Input
A plan’s phase breakdown maps cleanly onto assignable sprint work. The block below turns phases into estimates and owners.
1Phase 1 (Types): 1.5h → assign to @andi
2Phase 2 (Repository): 3h → assign to @andi
3Phase 3 (UseCase): 2h → assign to @citra
4Phase 4 (Handler): 2.5h → assign to @citra
5Phase 5 (Integration): 1h → pair: @andi + @citra
6Total: ~10h ≈ 1.5 daysThe phase structure is what makes parallel work possible: once you see which phases depend on which, you can hand independent phases to different developers instead of serializing the whole feature through one person.
08.11 Plan as Technical Documentation
Long after the feature ships, a good plan answers the “why” questions that otherwise require git archaeology. The block below lists the decisions it records.
1After project completion, plan.md explains:
2- Why GIN index and not pg_trgm?
3- Why a CASE expression and not separate queries?
4- Why the 'indonesian' dictionary and not 'simple'?
5- Why stock=0 products still appear in search?
6
7All decisions documented. New developers don't need to git-blame to understand.The lasting value is that plan.md plus clarifications.md form a decision record. A new engineer reads the rationale instead of reverse-engineering it from a suspicious-looking line in git blame.
08.12 Risk Assessment Quality
The risk section is only as useful as its mitigations, and there is a clear gap between a good one and a lazy one. The two blocks below contrast them.
1Risk: Indonesian FTS dictionary may not handle all Indonesian words
2Mitigation: Test with 1000 real product names from staging.
3 Fallback: use 'simple' dictionary if quality is inadequate.
4 Track search quality: SHOP-300That is a good risk entry — specific, testable, with a fallback and a tracking ticket. Compare it with the empty version below.
1Risk: Performance might be slow
2Mitigation: Will optimize if neededA mitigation with no concrete action is just a wish. When you review a plan, treat any “will optimize if needed” line as an unresolved risk and push it back until it names a real trigger and fallback.
08.13 Plan for Microservice Communication
For features that participate in an event-driven system, the plan documents the event contract explicitly. The section below defines produced and consumed events.
1## Event Contract Plan
2
3### Events PRODUCED by this service:
4None (read-only operation)
5
6### Events CONSUMED by this service:
7Topic: product.created, product.updated, product.deactivated
8Consumer Group: search-service-product-consumer
9Handler: Update search index entry
10Error: Log and continue (index lag acceptable per clarification Q3)Spelling out the contract prevents integration surprises: the plan states that search produces nothing and consumes three product events, so the boundary between services is settled before anyone writes a consumer.
08.14 When to Regenerate Plan
Not every change warrants a fresh plan. Regenerate when the foundation shifts:
- The spec changes significantly after clarification
- A constitution update affects this feature
- Tech review finds a major architectural issue
- A new library is chosen for implementation
Don’t regenerate for minor code-level changes that don’t touch the architecture. The heuristic: regenerate when a decision in the plan is now wrong, edit by hand when it is merely incomplete.
08.15 Plan Review Checklist for Tech Lead
When a plan reaches a tech lead, a structured checklist keeps the review fast and complete. The block below groups the checks by concern.
1Architecture:
2✅ Interfaces in the usecase package?
3✅ Dependency direction correct?
4✅ No ORM?
5
6SQL:
7✅ Indexes planned?
8✅ Parameterized queries only?
9✅ Migration is safe (CONCURRENTLY if on a live table)?
10
11Types:
12✅ uuid.UUID for IDs?
13✅ int64 for prices?
14✅ context.Context as the first parameter?
15
16Testing:
17✅ All ACs have a test case?
18✅ Error cases have tests?
19✅ Coverage target realistic?Running the same four-category checklist on every plan makes reviews consistent across the team — nobody has to remember the whole list, and no plan gets approved with an ORM sneaking in or an unparameterized query.
08.16 Tips & Gotchas
The habits below separate a plan you can implement from one that quietly misleads you:
💡 Tip 1: Review SQL in detail — AI generates valid SQL but not always optimal; check EXPLAIN ANALYZE.
💡 Tip 2: Verify interface signatures match existing patterns — align before task generation.
💡 Tip 3: Include plan.md in the spec PR — reviewers can verify the spec → plan translation.
💡 Tip 4: The plan is a living document — update it when implementation reveals surprises.
⚠️ Gotcha 1: A plan is never 100% accurate for new codebases — a more mature codebase yields a better plan.
⚠️ Gotcha 2: Complexity estimates can be off — the AI doesn’t know hidden complexity or team familiarity.
⚠️ Gotcha 3: Never accept SQL without review — it may have N+1 patterns, full scans, or missed indexes.
⚠️ Gotcha 4: An outdated plan produces wrong tasks — update the plan before regenerating tasks.
08.17 Smooth Transition to Tasks
Once the plan is validated and approved, the next command turns it into concrete work. The snippet below generates the task breakdown.
1# Only after the plan is validated and approved:
2specify tasks product-search
3# Reads plan.md → generates granular tasks with a clear DoDThe dependency is one-directional and strict: tasks are derived from the plan, so the plan must be final first. Generating tasks from a half-baked plan just means regenerating them again later.
08.18 Summary
specify plan transforms a business spec into an actionable technical blueprint — file structure, SQL schema, API design, test plan, and risk assessment.
Most important outputs: SQL queries ready for immediate review, interface signatures consistent with existing patterns, and a test plan mapped to every AC.
Required validation: architecture compliance, completeness (all ACs have tests), and SQL review — valid is not the same as optimal.
Living document: update the plan when implementation reveals surprises. A plan and an implementation that have diverged are technical debt.
In the next article, specify tasks — how Spec Kit breaks the plan into concrete, assignable, trackable tasks.