aidp 0.26.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +89 -0
  3. data/lib/aidp/cli/checkpoint_command.rb +198 -0
  4. data/lib/aidp/cli/config_command.rb +71 -0
  5. data/lib/aidp/cli/enhanced_input.rb +2 -0
  6. data/lib/aidp/cli/first_run_wizard.rb +8 -7
  7. data/lib/aidp/cli/harness_command.rb +102 -0
  8. data/lib/aidp/cli/jobs_command.rb +3 -3
  9. data/lib/aidp/cli/mcp_dashboard.rb +4 -3
  10. data/lib/aidp/cli/models_command.rb +661 -0
  11. data/lib/aidp/cli/providers_command.rb +223 -0
  12. data/lib/aidp/cli.rb +45 -464
  13. data/lib/aidp/config.rb +54 -0
  14. data/lib/aidp/daemon/runner.rb +2 -2
  15. data/lib/aidp/debug_mixin.rb +25 -10
  16. data/lib/aidp/execute/agent_signal_parser.rb +22 -0
  17. data/lib/aidp/execute/async_work_loop_runner.rb +2 -1
  18. data/lib/aidp/execute/checkpoint_display.rb +38 -37
  19. data/lib/aidp/execute/interactive_repl.rb +2 -1
  20. data/lib/aidp/execute/prompt_manager.rb +4 -4
  21. data/lib/aidp/execute/repl_macros.rb +2 -2
  22. data/lib/aidp/execute/steps.rb +94 -1
  23. data/lib/aidp/execute/work_loop_runner.rb +238 -19
  24. data/lib/aidp/execute/workflow_selector.rb +4 -27
  25. data/lib/aidp/firewall/provider_requirements_collector.rb +262 -0
  26. data/lib/aidp/harness/ai_decision_engine.rb +35 -2
  27. data/lib/aidp/harness/config_manager.rb +5 -10
  28. data/lib/aidp/harness/config_schema.rb +8 -0
  29. data/lib/aidp/harness/configuration.rb +40 -2
  30. data/lib/aidp/harness/enhanced_runner.rb +25 -19
  31. data/lib/aidp/harness/error_handler.rb +23 -73
  32. data/lib/aidp/harness/model_cache.rb +269 -0
  33. data/lib/aidp/harness/model_discovery_service.rb +259 -0
  34. data/lib/aidp/harness/model_registry.rb +201 -0
  35. data/lib/aidp/harness/provider_factory.rb +11 -2
  36. data/lib/aidp/harness/runner.rb +5 -0
  37. data/lib/aidp/harness/state_manager.rb +0 -7
  38. data/lib/aidp/harness/thinking_depth_manager.rb +202 -7
  39. data/lib/aidp/harness/ui/enhanced_tui.rb +8 -18
  40. data/lib/aidp/harness/ui/enhanced_workflow_selector.rb +0 -18
  41. data/lib/aidp/harness/ui/progress_display.rb +6 -2
  42. data/lib/aidp/harness/user_interface.rb +0 -58
  43. data/lib/aidp/init/runner.rb +7 -2
  44. data/lib/aidp/message_display.rb +0 -46
  45. data/lib/aidp/planning/analyzers/feedback_analyzer.rb +365 -0
  46. data/lib/aidp/planning/builders/agile_plan_builder.rb +387 -0
  47. data/lib/aidp/planning/builders/project_plan_builder.rb +193 -0
  48. data/lib/aidp/planning/generators/gantt_generator.rb +190 -0
  49. data/lib/aidp/planning/generators/iteration_plan_generator.rb +392 -0
  50. data/lib/aidp/planning/generators/legacy_research_planner.rb +473 -0
  51. data/lib/aidp/planning/generators/marketing_report_generator.rb +348 -0
  52. data/lib/aidp/planning/generators/mvp_scope_generator.rb +310 -0
  53. data/lib/aidp/planning/generators/user_test_plan_generator.rb +373 -0
  54. data/lib/aidp/planning/generators/wbs_generator.rb +259 -0
  55. data/lib/aidp/planning/mappers/persona_mapper.rb +163 -0
  56. data/lib/aidp/planning/parsers/document_parser.rb +141 -0
  57. data/lib/aidp/planning/parsers/feedback_data_parser.rb +252 -0
  58. data/lib/aidp/provider_manager.rb +8 -32
  59. data/lib/aidp/providers/adapter.rb +2 -4
  60. data/lib/aidp/providers/aider.rb +264 -0
  61. data/lib/aidp/providers/anthropic.rb +206 -121
  62. data/lib/aidp/providers/base.rb +123 -3
  63. data/lib/aidp/providers/capability_registry.rb +0 -1
  64. data/lib/aidp/providers/codex.rb +75 -70
  65. data/lib/aidp/providers/cursor.rb +87 -59
  66. data/lib/aidp/providers/gemini.rb +57 -60
  67. data/lib/aidp/providers/github_copilot.rb +19 -66
  68. data/lib/aidp/providers/kilocode.rb +35 -80
  69. data/lib/aidp/providers/opencode.rb +35 -80
  70. data/lib/aidp/setup/wizard.rb +555 -8
  71. data/lib/aidp/version.rb +1 -1
  72. data/lib/aidp/watch/build_processor.rb +211 -30
  73. data/lib/aidp/watch/change_request_processor.rb +128 -14
  74. data/lib/aidp/watch/ci_fix_processor.rb +103 -37
  75. data/lib/aidp/watch/ci_log_extractor.rb +258 -0
  76. data/lib/aidp/watch/github_state_extractor.rb +177 -0
  77. data/lib/aidp/watch/implementation_verifier.rb +284 -0
  78. data/lib/aidp/watch/plan_generator.rb +95 -52
  79. data/lib/aidp/watch/plan_processor.rb +7 -6
  80. data/lib/aidp/watch/repository_client.rb +245 -17
  81. data/lib/aidp/watch/review_processor.rb +100 -19
  82. data/lib/aidp/watch/reviewers/base_reviewer.rb +1 -1
  83. data/lib/aidp/watch/runner.rb +181 -29
  84. data/lib/aidp/watch/state_store.rb +22 -1
  85. data/lib/aidp/workflows/definitions.rb +147 -0
  86. data/lib/aidp/workflows/guided_agent.rb +3 -3
  87. data/lib/aidp/workstream_cleanup.rb +245 -0
  88. data/lib/aidp/worktree.rb +19 -0
  89. data/templates/aidp-development.yml.example +2 -2
  90. data/templates/aidp-production.yml.example +3 -3
  91. data/templates/aidp.yml.example +57 -0
  92. data/templates/implementation/generate_tdd_specs.md +213 -0
  93. data/templates/implementation/iterative_implementation.md +122 -0
  94. data/templates/planning/agile/analyze_feedback.md +183 -0
  95. data/templates/planning/agile/generate_iteration_plan.md +179 -0
  96. data/templates/planning/agile/generate_legacy_research_plan.md +171 -0
  97. data/templates/planning/agile/generate_marketing_report.md +162 -0
  98. data/templates/planning/agile/generate_mvp_scope.md +127 -0
  99. data/templates/planning/agile/generate_user_test_plan.md +143 -0
  100. data/templates/planning/agile/ingest_feedback.md +174 -0
  101. data/templates/planning/assemble_project_plan.md +113 -0
  102. data/templates/planning/assign_personas.md +108 -0
  103. data/templates/planning/create_tasks.md +52 -6
  104. data/templates/planning/generate_gantt.md +86 -0
  105. data/templates/planning/generate_wbs.md +85 -0
  106. data/templates/planning/initialize_planning_mode.md +70 -0
  107. data/templates/skills/README.md +2 -2
  108. data/templates/skills/marketing_strategist/SKILL.md +279 -0
  109. data/templates/skills/product_manager/SKILL.md +177 -0
  110. data/templates/skills/ruby_aidp_planning/SKILL.md +497 -0
  111. data/templates/skills/ruby_rspec_tdd/SKILL.md +514 -0
  112. data/templates/skills/ux_researcher/SKILL.md +222 -0
  113. metadata +47 -1
@@ -0,0 +1,245 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "worktree"
4
+ require_relative "workstream_state"
5
+ require "open3"
6
+ require "tty-prompt"
7
+
8
+ module Aidp
9
+ # Service for interactively cleaning up inactive workstreams
10
+ # Displays comprehensive status and prompts user for deletion decisions
11
+ class WorkstreamCleanup
12
+ class Error < StandardError; end
13
+
14
+ def initialize(project_dir: Dir.pwd, prompt: TTY::Prompt.new)
15
+ @project_dir = project_dir
16
+ @prompt = prompt
17
+ end
18
+
19
+ # Run interactive cleanup workflow
20
+ def run
21
+ Aidp.log_debug("workstream_cleanup", "start", project_dir: @project_dir)
22
+
23
+ workstreams = Aidp::Worktree.list(project_dir: @project_dir)
24
+
25
+ if workstreams.empty?
26
+ @prompt.say("No workstreams found.")
27
+ Aidp.log_debug("workstream_cleanup", "no_workstreams")
28
+ return
29
+ end
30
+
31
+ @prompt.say("Found #{workstreams.size} workstream(s)\n")
32
+
33
+ workstreams.each do |ws|
34
+ process_workstream(ws)
35
+ end
36
+
37
+ @prompt.say("\n✓ Cleanup complete")
38
+ Aidp.log_debug("workstream_cleanup", "complete")
39
+ end
40
+
41
+ private
42
+
43
+ def process_workstream(ws)
44
+ Aidp.log_debug("workstream_cleanup", "process", slug: ws[:slug])
45
+
46
+ status = gather_status(ws)
47
+ display_status(ws, status)
48
+
49
+ choice = prompt_action(ws, status)
50
+ execute_action(ws, choice, status)
51
+ end
52
+
53
+ def gather_status(ws)
54
+ Aidp.log_debug("workstream_cleanup", "gather_status", slug: ws[:slug])
55
+
56
+ status = {
57
+ exists: ws[:active],
58
+ state: Aidp::WorkstreamState.read(slug: ws[:slug], project_dir: @project_dir) || {}
59
+ }
60
+
61
+ return status unless status[:exists]
62
+
63
+ # Gather git status information
64
+ Dir.chdir(ws[:path]) do
65
+ status[:uncommitted_changes] = uncommitted_changes?
66
+ status[:unpushed_commits] = unpushed_commits?
67
+ status[:upstream_exists] = upstream_exists?
68
+ status[:last_commit_date] = last_commit_date
69
+ status[:behind_upstream] = behind_upstream? if status[:upstream_exists]
70
+ end
71
+
72
+ status
73
+ end
74
+
75
+ def uncommitted_changes?
76
+ stdout, _stderr, status = Open3.capture3("git", "status", "--porcelain")
77
+ status.success? && !stdout.strip.empty?
78
+ end
79
+
80
+ def unpushed_commits?
81
+ # Check if there are commits not in the upstream branch
82
+ stdout, _stderr, status = Open3.capture3("git", "log", "@{upstream}..", "--oneline")
83
+ status.success? && !stdout.strip.empty?
84
+ rescue
85
+ # If @{upstream} doesn't exist, check for any commits
86
+ false
87
+ end
88
+
89
+ def upstream_exists?
90
+ _stdout, _stderr, status = Open3.capture3("git", "rev-parse", "--abbrev-ref", "@{upstream}")
91
+ status.success?
92
+ end
93
+
94
+ def behind_upstream?
95
+ stdout, _stderr, status = Open3.capture3("git", "log", "..@{upstream}", "--oneline")
96
+ status.success? && !stdout.strip.empty?
97
+ end
98
+
99
+ def last_commit_date
100
+ stdout, _stderr, status = Open3.capture3("git", "log", "-1", "--format=%ci")
101
+ status.success? ? stdout.strip : nil
102
+ end
103
+
104
+ def display_status(ws, status)
105
+ @prompt.say("\n" + "=" * 60)
106
+ @prompt.say("Workstream: #{ws[:slug]}")
107
+ @prompt.say("=" * 60)
108
+ @prompt.say("Branch: #{ws[:branch]}")
109
+ @prompt.say("Created: #{ws[:created_at]}")
110
+ @prompt.say("Status: #{status[:state][:status] || "unknown"}")
111
+ @prompt.say("Iterations: #{status[:state][:iterations] || 0}")
112
+
113
+ if status[:state][:task]
114
+ @prompt.say("Task: #{status[:state][:task]}")
115
+ end
116
+
117
+ unless status[:exists]
118
+ @prompt.say("\n⚠️ Worktree directory does not exist")
119
+ return
120
+ end
121
+
122
+ # Display git status
123
+ @prompt.say("\nGit Status:")
124
+ @prompt.say(" Uncommitted changes: #{status[:uncommitted_changes] ? "Yes" : "No"}")
125
+
126
+ if status[:upstream_exists]
127
+ @prompt.say(" Upstream: exists")
128
+ @prompt.say(" Unpushed commits: #{status[:unpushed_commits] ? "Yes" : "No"}")
129
+ @prompt.say(" Behind upstream: #{status[:behind_upstream] ? "Yes" : "No"}")
130
+ else
131
+ @prompt.say(" Upstream: none (local branch)")
132
+ end
133
+
134
+ if status[:last_commit_date]
135
+ @prompt.say(" Last commit: #{status[:last_commit_date]}")
136
+ end
137
+ end
138
+
139
+ def prompt_action(ws, status)
140
+ Aidp.log_debug("workstream_cleanup", "prompt_action", slug: ws[:slug])
141
+
142
+ choices = build_choices(ws, status)
143
+ @prompt.select("\nWhat would you like to do?", choices, per_page: 10)
144
+ end
145
+
146
+ def build_choices(ws, status)
147
+ choices = [
148
+ {name: "Keep (skip)", value: :keep},
149
+ {name: "Delete worktree only", value: :delete_worktree}
150
+ ]
151
+
152
+ if status[:exists]
153
+ choices << if has_risk_factors?(status)
154
+ {name: "Delete worktree and local branch (has uncommitted/unpushed work!)", value: :delete_all}
155
+ else
156
+ {name: "Delete worktree and local branch", value: :delete_all}
157
+ end
158
+
159
+ if status[:upstream_exists]
160
+ choices << {name: "Delete worktree, local branch, and remote branch", value: :delete_all_remote}
161
+ end
162
+ else
163
+ choices << {name: "Delete registration (worktree already gone)", value: :delete_worktree}
164
+ end
165
+
166
+ choices
167
+ end
168
+
169
+ def has_risk_factors?(status)
170
+ status[:uncommitted_changes] || status[:unpushed_commits]
171
+ end
172
+
173
+ def execute_action(ws, choice, status)
174
+ Aidp.log_debug("workstream_cleanup", "execute_action", slug: ws[:slug], action: choice)
175
+
176
+ case choice
177
+ when :keep
178
+ @prompt.say("Keeping workstream")
179
+ when :delete_worktree
180
+ delete_worktree(ws, delete_branch: false)
181
+ when :delete_all
182
+ if confirm_deletion(ws, status, remote: false)
183
+ delete_worktree(ws, delete_branch: true)
184
+ else
185
+ @prompt.say("Deletion cancelled")
186
+ end
187
+ when :delete_all_remote
188
+ if confirm_deletion(ws, status, remote: true)
189
+ delete_remote_branch(ws)
190
+ delete_worktree(ws, delete_branch: true)
191
+ else
192
+ @prompt.say("Deletion cancelled")
193
+ end
194
+ end
195
+ end
196
+
197
+ def confirm_deletion(ws, status, remote:)
198
+ if has_risk_factors?(status)
199
+ warning = "⚠️ WARNING: This workstream has uncommitted changes or unpushed commits!"
200
+ @prompt.say("\n#{warning}")
201
+ end
202
+
203
+ message = if remote
204
+ "Delete worktree, local branch, AND remote branch for '#{ws[:slug]}'?"
205
+ else
206
+ "Delete worktree and local branch for '#{ws[:slug]}'?"
207
+ end
208
+
209
+ @prompt.yes?(message)
210
+ end
211
+
212
+ def delete_remote_branch(ws)
213
+ Aidp.log_debug("workstream_cleanup", "delete_remote_branch", slug: ws[:slug], branch: ws[:branch])
214
+
215
+ # Extract remote and branch name
216
+ # Branch format is typically "aidp/slug", we need to push to origin
217
+ Dir.chdir(@project_dir) do
218
+ _, stderr, status = Open3.capture3("git", "push", "origin", "--delete", ws[:branch])
219
+ if status.success?
220
+ @prompt.say("✓ Deleted remote branch: #{ws[:branch]}")
221
+ else
222
+ @prompt.say("⚠️ Failed to delete remote branch: #{stderr.strip}")
223
+ Aidp.log_debug("workstream_cleanup", "delete_remote_failed", branch: ws[:branch], error: stderr.strip)
224
+ end
225
+ end
226
+ end
227
+
228
+ def delete_worktree(ws, delete_branch:)
229
+ Aidp.log_debug("workstream_cleanup", "delete_worktree", slug: ws[:slug], delete_branch: delete_branch)
230
+
231
+ begin
232
+ Aidp::Worktree.remove(
233
+ slug: ws[:slug],
234
+ project_dir: @project_dir,
235
+ delete_branch: delete_branch
236
+ )
237
+ @prompt.say("✓ Deleted workstream: #{ws[:slug]}")
238
+ @prompt.say(" Branch deleted") if delete_branch
239
+ rescue Aidp::Worktree::Error => e
240
+ @prompt.say("❌ Error: #{e.message}")
241
+ Aidp.log_error("workstream_cleanup", "delete_failed", slug: ws[:slug], error: e.message)
242
+ end
243
+ end
244
+ end
245
+ end
data/lib/aidp/worktree.rb CHANGED
@@ -141,6 +141,25 @@ module Aidp
141
141
  !info(slug: slug, project_dir: project_dir).nil?
142
142
  end
143
143
 
144
+ # Find a worktree by branch name
145
+ #
146
+ # @param branch [String] Branch name to search for
147
+ # @param project_dir [String] Project root directory
148
+ # @return [Hash, nil] Worktree info or nil if not found
149
+ def find_by_branch(branch:, project_dir: Dir.pwd)
150
+ registry = load_registry(project_dir)
151
+ slug, data = registry.find { |_slug, info| info["branch"] == branch }
152
+ return nil unless data
153
+
154
+ {
155
+ slug: slug,
156
+ path: data["path"],
157
+ branch: data["branch"],
158
+ created_at: data["created_at"],
159
+ active: Dir.exist?(data["path"])
160
+ }
161
+ end
162
+
144
163
  private
145
164
 
146
165
  # Ensure we're in a git repository
@@ -137,7 +137,7 @@ providers:
137
137
  file_upload: true
138
138
  code_generation: true
139
139
  analysis: true
140
- streaming: true
140
+ supports_json_mode: true
141
141
 
142
142
  # Monitoring configuration (enhanced for development)
143
143
  monitoring:
@@ -243,7 +243,7 @@ providers:
243
243
  code_generation: true
244
244
  analysis: true
245
245
  vision: true
246
- streaming: true
246
+ supports_json_mode: true
247
247
  function_calling: true
248
248
  tool_use: true
249
249
 
@@ -149,7 +149,7 @@ providers:
149
149
  code_generation: true
150
150
  analysis: true
151
151
  vision: true
152
- streaming: true
152
+ supports_json_mode: true
153
153
  function_calling: true
154
154
  tool_use: true
155
155
 
@@ -254,7 +254,7 @@ providers:
254
254
  file_upload: true
255
255
  code_generation: true
256
256
  analysis: true
257
- streaming: true
257
+ supports_json_mode: true
258
258
 
259
259
  # Monitoring configuration
260
260
  monitoring:
@@ -365,7 +365,7 @@ providers:
365
365
  code_generation: true
366
366
  analysis: true
367
367
  vision: true
368
- streaming: true
368
+ supports_json_mode: true
369
369
 
370
370
  # Monitoring configuration
371
371
  monitoring:
@@ -239,6 +239,25 @@ providers:
239
239
  flags: ["--precise"]
240
240
  timeout: 900 # 15 minutes
241
241
 
242
+ # Thinking tier model configuration
243
+ # Maps thinking depth tiers to specific models for this provider
244
+ thinking_tiers:
245
+ mini:
246
+ models:
247
+ - cursor-fast # Fast model for simple tasks
248
+ standard:
249
+ models:
250
+ - cursor-default # Default model for standard tasks
251
+ thinking:
252
+ models:
253
+ - cursor-precise # Precise model for complex reasoning
254
+ pro:
255
+ models:
256
+ - cursor-precise # Use best model for pro tier
257
+ max:
258
+ models:
259
+ - cursor-precise # Use best model for max tier
260
+
242
261
  # Provider features
243
262
  features:
244
263
  file_upload: true
@@ -343,6 +362,25 @@ providers:
343
362
  max_tokens: 200000
344
363
  timeout: 600 # 10 minutes
345
364
 
365
+ # Thinking tier model configuration
366
+ # Maps thinking depth tiers to specific models for this provider
367
+ thinking_tiers:
368
+ mini:
369
+ models:
370
+ - claude-3-5-haiku-20241022 # Fastest, cheapest model
371
+ standard:
372
+ models:
373
+ - claude-3-5-sonnet-20241022 # Balanced performance
374
+ thinking:
375
+ models:
376
+ - claude-3-5-sonnet-20241022 # Best balance for complex tasks
377
+ pro:
378
+ models:
379
+ - claude-3-opus-20240229 # Most capable model
380
+ max:
381
+ models:
382
+ - claude-3-opus-20240229 # Maximum capability
383
+
346
384
  # Authentication configuration
347
385
  auth:
348
386
  api_key_env: "ANTHROPIC_API_KEY" # Environment variable for API key
@@ -394,6 +432,25 @@ providers:
394
432
  max_tokens: 30000
395
433
  timeout: 300 # 5 minutes
396
434
 
435
+ # Thinking tier model configuration
436
+ # Maps thinking depth tiers to specific models for this provider
437
+ thinking_tiers:
438
+ mini:
439
+ models:
440
+ - gemini-1.5-flash # Fast model for simple tasks
441
+ standard:
442
+ models:
443
+ - gemini-1.5-pro # Most capable model
444
+ thinking:
445
+ models:
446
+ - gemini-1.5-pro # Best model for complex reasoning
447
+ pro:
448
+ models:
449
+ - gemini-1.5-pro # Use best available
450
+ max:
451
+ models:
452
+ - gemini-1.5-pro # Use best available
453
+
397
454
  # Authentication configuration
398
455
  auth:
399
456
  api_key_env: "GEMINI_API_KEY" # Environment variable for API key
@@ -0,0 +1,213 @@
1
+ # Generate TDD Test Specifications
2
+
3
+ You are creating **test specifications** following Test-Driven Development (TDD) principles.
4
+
5
+ ## TDD Philosophy
6
+
7
+ ### RED → GREEN → REFACTOR
8
+
9
+ 1. **RED**: Write failing tests that specify desired behavior
10
+ 2. **GREEN**: Write minimal code to make tests pass
11
+ 3. **REFACTOR**: Improve code while keeping tests green
12
+
13
+ ## Context
14
+
15
+ Read these artifacts to understand requirements:
16
+
17
+ - `.aidp/docs/PRD.md` - Product requirements (if exists)
18
+ - `.aidp/docs/TECH_DESIGN.md` - Technical design (if exists)
19
+ - `.aidp/docs/TASK_LIST.md` - Task breakdown (if exists)
20
+ - `.aidp/docs/WBS.md` - Work breakdown structure (if exists)
21
+
22
+ ## Your Task
23
+
24
+ Generate comprehensive test specifications BEFORE implementation.
25
+
26
+ ## Test Specification Structure
27
+
28
+ Create `docs/tdd_specifications.md`:
29
+
30
+ ```markdown
31
+ # TDD Test Specifications
32
+
33
+ Generated: <timestamp>
34
+
35
+ ## Overview
36
+
37
+ This document defines tests to write BEFORE implementing features.
38
+ Follow TDD: write tests first, watch them fail, then implement.
39
+
40
+ ## Test Categories
41
+
42
+ ### Unit Tests
43
+
44
+ #### Feature: [Feature Name]
45
+
46
+ **Test Cases:**
47
+ 1. **should handle valid input**
48
+ - Given: Valid input parameters
49
+ - When: Feature is invoked
50
+ - Then: Returns expected output
51
+ - Status: ⭕ Not yet written
52
+
53
+ 2. **should reject invalid input**
54
+ - Given: Invalid parameters
55
+ - When: Feature is invoked
56
+ - Then: Raises appropriate error
57
+ - Status: ⭕ Not yet written
58
+
59
+ 3. **should handle edge cases**
60
+ - Given: Edge case inputs (empty, nil, boundary values)
61
+ - When: Feature is invoked
62
+ - Then: Handles gracefully
63
+ - Status: ⭕ Not yet written
64
+
65
+ ### Integration Tests
66
+
67
+ #### Integration: [Component A + Component B]
68
+
69
+ **Test Cases:**
70
+ 1. **should integrate successfully**
71
+ - Given: Both components configured
72
+ - When: Integration point is called
73
+ - Then: Data flows correctly
74
+ - Status: ⭕ Not yet written
75
+
76
+ ### Acceptance Tests
77
+
78
+ #### User Story: [As a user, I want to...]
79
+
80
+ **Test Cases:**
81
+ 1. **should complete user workflow**
82
+ - Given: User starts workflow
83
+ - When: User performs actions
84
+ - Then: Achieves expected outcome
85
+ - Status: ⭕ Not yet written
86
+
87
+ ## Test Implementation Order
88
+
89
+ 1. **Phase 1: Critical Path**
90
+ - Write tests for core functionality first
91
+ - Focus on happy path
92
+ - Estimated: X hours
93
+
94
+ 2. **Phase 2: Edge Cases**
95
+ - Add tests for error conditions
96
+ - Boundary testing
97
+ - Estimated: Y hours
98
+
99
+ 3. **Phase 3: Integration**
100
+ - Test component interactions
101
+ - End-to-end workflows
102
+ - Estimated: Z hours
103
+
104
+ ## Coverage Goals
105
+
106
+ - **Unit Tests:** 90%+ coverage
107
+ - **Integration Tests:** All integration points
108
+ - **Acceptance Tests:** All user stories from PRD
109
+
110
+ ## Notes
111
+
112
+ - Tests should be **fast** (< 1s per test ideal)
113
+ - Tests should be **isolated** (no shared state)
114
+ - Tests should be **deterministic** (same result every time)
115
+ - Mock external dependencies (APIs, databases, file I/O)
116
+ - Test behavior, not implementation
117
+
118
+ ## Next Steps
119
+
120
+ 1. Review this specification
121
+ 2. Write tests (they should fail - RED)
122
+ 3. Implement minimal code (make tests pass - GREEN)
123
+ 4. Refactor code (keep tests green - REFACTOR)
124
+ ```
125
+
126
+ ## TDD Best Practices
127
+
128
+ ### 1. Test One Thing
129
+
130
+ Each test should verify ONE behavior.
131
+
132
+ ❌ BAD: Testing multiple behaviors in one test
133
+ ✅ GOOD: Separate tests for separate behaviors
134
+
135
+ ### 2. Use Descriptive Names
136
+
137
+ Test names should describe the behavior being tested, not implementation details.
138
+
139
+ ### 3. Follow Given-When-Then
140
+
141
+ Structure tests clearly:
142
+
143
+ - **GIVEN**: Setup test data and preconditions
144
+ - **WHEN**: Execute the behavior being tested
145
+ - **THEN**: Verify expected outcomes
146
+
147
+ ### 4. Mock External Dependencies
148
+
149
+ Don't hit real APIs, databases, or file systems in unit tests.
150
+ Use test doubles/mocks for external dependencies.
151
+
152
+ ### 5. Test Behavior, Not Implementation
153
+
154
+ ❌ BAD: Testing that internal helper methods are called
155
+ ✅ GOOD: Testing that public interface returns correct results
156
+
157
+ ## Framework-Specific Implementation
158
+
159
+ **For language/framework-specific test generation, use the appropriate skill:**
160
+
161
+ - **Ruby/RSpec**: Use `ruby_rspec_tdd` skill for RSpec-specific test files, fixtures, and syntax
162
+ - **Python/pytest**: Use `python_pytest_tdd` skill for pytest-specific implementation
163
+ - **JavaScript/Jest**: Use `javascript_jest_tdd` skill for Jest-specific implementation
164
+ - **Other frameworks**: Use ZFC skill matching to find appropriate testing skill
165
+
166
+ ## Skill Delegation
167
+
168
+ After creating the language-agnostic test specification above, delegate to the framework-specific skill to generate:
169
+
170
+ 1. **Skeleton test files** in the framework's directory structure and naming conventions
171
+ 2. **Test fixtures** or factories in the framework's format
172
+ 3. **Test execution commands** for the specific framework
173
+ 4. **Framework-specific examples** and best practices
174
+
175
+ **Example skill invocation:**
176
+
177
+ For a Ruby project using RSpec:
178
+
179
+ ```text
180
+ Use the `ruby_rspec_tdd` skill to:
181
+ 1. Generate skeleton RSpec test files in spec/ directory
182
+ 2. Create FactoryBot factories or fixtures as needed
183
+ 3. Provide RSpec-specific examples and matchers
184
+ 4. Include bundle exec rspec execution commands
185
+ ```
186
+
187
+ For a Python project using pytest:
188
+
189
+ ```text
190
+ Use the `python_pytest_tdd` skill to:
191
+ 1. Generate skeleton pytest test files in tests/ directory
192
+ 2. Create pytest fixtures as needed
193
+ 3. Provide pytest-specific examples and assertions
194
+ 4. Include pytest execution commands
195
+ ```
196
+
197
+ ## Output Files
198
+
199
+ Generate:
200
+
201
+ 1. **`docs/tdd_specifications.md`** - Framework-agnostic test specifications (as shown above)
202
+ 2. **Framework-specific test files** - Via appropriate skill delegation
203
+ 3. **Test data/fixtures** - Via appropriate skill delegation
204
+
205
+ ## Remember
206
+
207
+ - **Write tests FIRST** - before any implementation
208
+ - **Watch tests FAIL** - ensure they actually test something
209
+ - **Write minimal code** - just enough to pass tests
210
+ - **Refactor** - improve code with confidence (tests protect you)
211
+ - **Use skills for framework-specific implementation** - keep this template language-agnostic
212
+
213
+ **TDD gives you confidence, better design, and executable documentation!** 🧪