aidp 0.16.0 → 0.17.1

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/lib/aidp/analyze/error_handler.rb +32 -13
  3. data/lib/aidp/analyze/kb_inspector.rb +2 -3
  4. data/lib/aidp/analyze/progress.rb +6 -11
  5. data/lib/aidp/cli/mcp_dashboard.rb +1 -1
  6. data/lib/aidp/cli.rb +300 -33
  7. data/lib/aidp/config.rb +1 -1
  8. data/lib/aidp/execute/async_work_loop_runner.rb +2 -1
  9. data/lib/aidp/execute/checkpoint.rb +1 -1
  10. data/lib/aidp/execute/future_work_backlog.rb +1 -1
  11. data/lib/aidp/execute/progress.rb +6 -9
  12. data/lib/aidp/execute/repl_macros.rb +79 -10
  13. data/lib/aidp/harness/config_loader.rb +2 -2
  14. data/lib/aidp/harness/config_validator.rb +1 -1
  15. data/lib/aidp/harness/enhanced_runner.rb +16 -7
  16. data/lib/aidp/harness/error_handler.rb +12 -5
  17. data/lib/aidp/harness/provider_manager.rb +4 -19
  18. data/lib/aidp/harness/runner.rb +2 -2
  19. data/lib/aidp/harness/state/persistence.rb +9 -10
  20. data/lib/aidp/harness/state/workflow_state.rb +3 -2
  21. data/lib/aidp/harness/state_manager.rb +33 -97
  22. data/lib/aidp/harness/status_display.rb +22 -12
  23. data/lib/aidp/harness/ui/enhanced_tui.rb +3 -4
  24. data/lib/aidp/harness/user_interface.rb +11 -6
  25. data/lib/aidp/jobs/background_runner.rb +8 -2
  26. data/lib/aidp/logger.rb +1 -1
  27. data/lib/aidp/message_display.rb +9 -2
  28. data/lib/aidp/providers/anthropic.rb +1 -1
  29. data/lib/aidp/providers/base.rb +4 -4
  30. data/lib/aidp/providers/codex.rb +1 -1
  31. data/lib/aidp/providers/cursor.rb +1 -1
  32. data/lib/aidp/providers/gemini.rb +1 -1
  33. data/lib/aidp/providers/github_copilot.rb +1 -1
  34. data/lib/aidp/providers/macos_ui.rb +1 -1
  35. data/lib/aidp/providers/opencode.rb +1 -1
  36. data/lib/aidp/skills/registry.rb +31 -29
  37. data/lib/aidp/skills/router.rb +178 -0
  38. data/lib/aidp/skills/wizard/builder.rb +141 -0
  39. data/lib/aidp/skills/wizard/controller.rb +145 -0
  40. data/lib/aidp/skills/wizard/differ.rb +232 -0
  41. data/lib/aidp/skills/wizard/prompter.rb +317 -0
  42. data/lib/aidp/skills/wizard/template_library.rb +164 -0
  43. data/lib/aidp/skills/wizard/writer.rb +105 -0
  44. data/lib/aidp/version.rb +1 -1
  45. data/lib/aidp/watch/plan_generator.rb +1 -1
  46. data/lib/aidp/watch/repository_client.rb +13 -9
  47. data/lib/aidp/workflows/guided_agent.rb +2 -312
  48. data/lib/aidp/workstream_executor.rb +8 -2
  49. data/templates/skills/README.md +334 -0
  50. data/templates/skills/architecture_analyst/SKILL.md +173 -0
  51. data/templates/skills/product_strategist/SKILL.md +141 -0
  52. data/templates/skills/repository_analyst/SKILL.md +117 -0
  53. data/templates/skills/test_analyzer/SKILL.md +213 -0
  54. metadata +13 -1
@@ -201,79 +201,10 @@ module Aidp
201
201
  goal
202
202
  end
203
203
 
204
- def analyze_user_intent(user_goal)
205
- display_message("\nšŸ” Analyzing your request...", type: :info)
206
-
207
- # Build the system prompt with AIDP capabilities
208
- system_prompt = build_system_prompt
209
-
210
- # Build the user prompt
211
- user_prompt = build_analysis_prompt(user_goal)
212
-
213
- # Call provider to analyze intent
214
- response = call_provider_for_analysis(system_prompt, user_prompt)
215
-
216
- # Parse the response
217
- parse_recommendation(response)
218
- end
219
-
220
- def build_system_prompt
221
- # Try to load from project dir first, fall back to gem's docs
222
- capabilities_path = File.join(@project_dir, "docs", "AIDP_CAPABILITIES.md")
223
- unless File.exist?(capabilities_path)
224
- # Use the gem's copy
225
- gem_root = File.expand_path("../../..", __dir__)
226
- capabilities_path = File.join(gem_root, "docs", "AIDP_CAPABILITIES.md")
227
- end
228
-
229
- capabilities_doc = File.read(capabilities_path)
230
-
231
- <<~PROMPT
232
- You are an expert AI assistant helping users select the right AIDP workflow for their needs.
233
-
234
- Your role:
235
- 1. Understand what the user wants to accomplish
236
- 2. Match their intent to AIDP's capabilities
237
- 3. Recommend the most appropriate workflow
238
- 4. Explain why this workflow fits their needs
239
- 5. Identify if custom steps or templates are needed
240
-
241
- AIDP Capabilities Reference:
242
- #{capabilities_doc}
243
-
244
- Response Format:
245
- Provide a JSON response with:
246
- {
247
- "mode": "analyze|execute|hybrid",
248
- "workflow_key": "specific_workflow_key",
249
- "reasoning": "brief explanation of why this fits",
250
- "additional_steps": ["any", "custom", "steps", "if", "needed"],
251
- "questions": ["any", "clarifying", "questions"],
252
- "confidence": "high|medium|low"
253
- }
254
-
255
- Be concise to preserve the user's context window.
256
- PROMPT
257
- end
258
-
259
- def build_analysis_prompt(user_goal)
260
- <<~PROMPT
261
- User Goal: #{user_goal}
262
-
263
- Analyze this goal and recommend the most appropriate AIDP workflow.
264
- Consider:
265
- - Is this analysis or development?
266
- - What level of rigor is needed?
267
- - Are there any gaps in existing workflows?
268
-
269
- Provide your recommendation in JSON format.
270
- PROMPT
271
- end
272
-
273
204
  def call_provider_for_analysis(system_prompt, user_prompt)
274
205
  attempts = 0
275
206
  max_attempts = (@provider_manager.respond_to?(:configured_providers) ? @provider_manager.configured_providers.size : 2)
276
- max_attempts = 2 if max_attempts < 2 # at least one retry if a fallback exists
207
+ max_attempts = 2 if max_attempts < 2
277
208
 
278
209
  begin
279
210
  attempts += 1
@@ -283,7 +214,6 @@ module Aidp
283
214
  raise ConversationError, "No provider configured for guided workflow"
284
215
  end
285
216
 
286
- # Create provider instance using ProviderFactory
287
217
  provider_factory = Aidp::Harness::ProviderFactory.new(@config_manager)
288
218
  provider = provider_factory.create_provider(provider_name, prompt: @prompt)
289
219
 
@@ -292,7 +222,7 @@ module Aidp
292
222
  end
293
223
 
294
224
  combined_prompt = "#{system_prompt}\n\n#{user_prompt}"
295
- result = provider.send(prompt: combined_prompt)
225
+ result = provider.send_message(prompt: combined_prompt)
296
226
 
297
227
  if result.nil? || result.empty?
298
228
  raise ConversationError, "Provider request failed: empty response"
@@ -319,20 +249,6 @@ module Aidp
319
249
  end
320
250
  end
321
251
 
322
- def parse_recommendation(response_text)
323
- # Extract JSON from response (might be wrapped in markdown code blocks)
324
- json_match = response_text.match(/```json\s*(\{.*?\})\s*```/m) ||
325
- response_text.match(/(\{.*\})/m)
326
-
327
- unless json_match
328
- raise ConversationError, "Could not parse recommendation from response"
329
- end
330
-
331
- JSON.parse(json_match[1], symbolize_names: true)
332
- rescue JSON::ParserError => e
333
- raise ConversationError, "Invalid JSON in recommendation: #{e.message}"
334
- end
335
-
336
252
  def validate_provider_configuration!
337
253
  configured = @provider_manager.configured_providers
338
254
  if configured.nil? || configured.empty?
@@ -349,232 +265,6 @@ module Aidp
349
265
  end
350
266
  end
351
267
 
352
- def present_recommendation(recommendation)
353
- display_message("\n✨ Recommendation", type: :highlight)
354
- display_message("─" * 60, type: :muted)
355
-
356
- mode = recommendation[:mode].to_sym
357
- workflow_key = recommendation[:workflow_key].to_sym
358
-
359
- # Get workflow details
360
- workflow = Definitions.get_workflow(mode, workflow_key)
361
-
362
- unless workflow
363
- # Handle custom workflow or error
364
- return handle_custom_workflow(recommendation)
365
- end
366
-
367
- # Display the recommendation
368
- display_message("Mode: #{mode.to_s.capitalize}", type: :info)
369
- display_message("Workflow: #{workflow[:name]}", type: :info)
370
- display_message("\n#{workflow[:description]}", type: :muted)
371
- display_message("\nReasoning: #{recommendation[:reasoning]}\n", type: :info)
372
-
373
- # Show what's included
374
- display_message("This workflow includes:", type: :highlight)
375
- workflow[:details].each do |detail|
376
- display_message(" • #{detail}", type: :info)
377
- end
378
-
379
- # Handle additional steps if needed
380
- steps = workflow[:steps]
381
- if recommendation[:additional_steps]&.any?
382
- display_message("\nAdditional custom steps recommended:", type: :highlight)
383
- recommendation[:additional_steps].each do |step|
384
- display_message(" • #{step}", type: :info)
385
- end
386
- steps = workflow[:steps] + recommendation[:additional_steps]
387
- end
388
-
389
- # Ask for confirmation
390
- display_message("")
391
- confirmed = @prompt.yes?("Does this workflow fit your needs?")
392
-
393
- if confirmed
394
- {
395
- mode: mode,
396
- workflow_key: workflow_key,
397
- workflow_type: workflow_key,
398
- steps: steps,
399
- user_input: @user_input,
400
- workflow: workflow
401
- }
402
- else
403
- # Offer alternatives
404
- offer_alternatives(mode)
405
- end
406
- end
407
-
408
- def handle_custom_workflow(recommendation)
409
- display_message("\nšŸ’” Custom Workflow Needed", type: :highlight)
410
- display_message("The AI recommends creating a custom workflow:\n", type: :info)
411
- display_message(recommendation[:reasoning], type: :muted)
412
-
413
- if recommendation[:questions]&.any?
414
- display_message("\nLet me gather some more information:\n", type: :highlight)
415
- recommendation[:questions].each do |question|
416
- answer = @prompt.ask(question)
417
- @user_input[question.downcase.gsub(/\s+/, "_").to_sym] = answer
418
- end
419
- end
420
-
421
- # Let user select from available steps
422
- mode = recommendation[:mode].to_sym
423
- display_message("\nLet's build a custom workflow by selecting specific steps:", type: :info)
424
-
425
- steps = select_custom_steps(mode, recommendation[:additional_steps])
426
-
427
- {
428
- mode: mode,
429
- workflow_key: :custom,
430
- workflow_type: :custom,
431
- steps: steps,
432
- user_input: @user_input,
433
- workflow: {
434
- name: "Custom Workflow",
435
- description: recommendation[:reasoning],
436
- details: steps
437
- }
438
- }
439
- end
440
-
441
- def select_custom_steps(mode, suggested_steps = [])
442
- # Get available steps for the mode
443
- spec = case mode
444
- when :analyze
445
- Aidp::Analyze::Steps::SPEC
446
- when :execute
447
- Aidp::Execute::Steps::SPEC
448
- when :hybrid
449
- # Combine both
450
- Aidp::Analyze::Steps::SPEC.merge(Aidp::Execute::Steps::SPEC)
451
- else
452
- {}
453
- end
454
-
455
- step_choices = spec.map do |step_key, step_spec|
456
- {
457
- name: "#{step_key} - #{step_spec["description"]}",
458
- value: step_key
459
- }
460
- end
461
-
462
- # Pre-select suggested steps
463
- default_indices = suggested_steps.map do |step|
464
- step_choices.index { |choice| choice[:value].to_s == step.to_s }
465
- end.compact
466
-
467
- selected_steps = @prompt.multi_select(
468
- "Select steps for your custom workflow:",
469
- step_choices,
470
- default: default_indices,
471
- per_page: 20
472
- )
473
-
474
- selected_steps.empty? ? suggested_steps : selected_steps
475
- end
476
-
477
- def offer_alternatives(current_mode)
478
- display_message("\nšŸ”„ Let's find a better fit", type: :highlight)
479
-
480
- choices = [
481
- {name: "Try a different #{current_mode} workflow", value: :different_workflow},
482
- {name: "Switch to a different mode", value: :different_mode},
483
- {name: "Build a custom workflow", value: :custom},
484
- {name: "Start over", value: :restart}
485
- ]
486
-
487
- choice = @prompt.select("What would you like to do?", choices)
488
-
489
- case choice
490
- when :different_workflow
491
- select_manual_workflow(current_mode)
492
- when :different_mode
493
- # Let user pick mode manually then workflow
494
- new_mode = @prompt.select(
495
- "Select mode:",
496
- {
497
- "šŸ”¬ Analyze Mode" => :analyze,
498
- "šŸ—ļø Execute Mode" => :execute,
499
- "šŸ”€ Hybrid Mode" => :hybrid
500
- }
501
- )
502
- select_manual_workflow(new_mode)
503
- when :custom
504
- select_custom_steps(current_mode)
505
- when :restart
506
- select_workflow # Recursive call to start over
507
- end
508
- end
509
-
510
- def select_manual_workflow(mode)
511
- workflows = Definitions.workflows_for_mode(mode)
512
-
513
- choices = workflows.map do |key, workflow|
514
- {
515
- name: "#{workflow[:icon]} #{workflow[:name]} - #{workflow[:description]}",
516
- value: key
517
- }
518
- end
519
-
520
- selected_key = @prompt.select("Choose a workflow:", choices, per_page: 15)
521
- workflow = workflows[selected_key]
522
-
523
- {
524
- mode: mode,
525
- workflow_key: selected_key,
526
- workflow_type: selected_key,
527
- steps: workflow[:steps],
528
- user_input: @user_input,
529
- workflow: workflow
530
- }
531
- end
532
-
533
- def collect_workflow_details(workflow_selection)
534
- # Collect additional information based on mode
535
- case workflow_selection[:mode]
536
- when :execute
537
- collect_execute_details
538
- when :analyze
539
- # Analyze mode typically doesn't need much user input
540
- @user_input[:analysis_goal] = @user_input[:original_goal]
541
- when :hybrid
542
- collect_execute_details # Hybrid often needs project details
543
- end
544
-
545
- # Update the workflow selection with collected input
546
- workflow_selection[:user_input] = @user_input
547
- end
548
-
549
- def collect_execute_details
550
- return if @user_input[:project_description] # Already collected
551
-
552
- display_message("\nšŸ“ Project Information", type: :highlight)
553
- display_message("Let me gather some details for the PRD:\n", type: :info)
554
-
555
- @user_input[:project_description] = @prompt.ask(
556
- "Describe what you're building (can reference your original goal):",
557
- default: @user_input[:original_goal]
558
- )
559
-
560
- @user_input[:tech_stack] = @prompt.ask(
561
- "Tech stack (e.g., Ruby/Rails, Node.js, Python)? [optional]",
562
- required: false
563
- )
564
-
565
- @user_input[:target_users] = @prompt.ask(
566
- "Who will use this? [optional]",
567
- required: false
568
- )
569
-
570
- @user_input[:success_criteria] = @prompt.ask(
571
- "How will you measure success? [optional]",
572
- required: false
573
- )
574
- end
575
-
576
- # Plan-then-execute helper methods
577
-
578
268
  def build_planning_system_prompt
579
269
  <<~PROMPT
580
270
  You are a planning assistant helping gather requirements through clarifying questions.
@@ -25,11 +25,17 @@ module Aidp
25
25
  keyword_init: true
26
26
  )
27
27
 
28
- def initialize(project_dir: Dir.pwd, max_concurrent: 3)
28
+ # @param project_dir [String] root directory of the project
29
+ # @param max_concurrent [Integer] maximum number of concurrent workstreams (thread pool size)
30
+ # @param runner_factory [Proc] factory that builds a harness runner. Signature: (path, mode, options) => object responding to #run
31
+ def initialize(project_dir: Dir.pwd, max_concurrent: 3, runner_factory: nil)
29
32
  @project_dir = project_dir
30
33
  @max_concurrent = max_concurrent
31
34
  @results = Concurrent::Hash.new
32
35
  @start_times = Concurrent::Hash.new
36
+ @runner_factory = runner_factory || lambda do |path, mode, options|
37
+ Aidp::Harness::Runner.new(path, mode, options)
38
+ end
33
39
  end
34
40
 
35
41
  # Execute multiple workstreams in parallel
@@ -120,7 +126,7 @@ module Aidp
120
126
  Dir.chdir(workstream[:path])
121
127
 
122
128
  # Execute harness
123
- runner = Aidp::Harness::Runner.new(
129
+ runner = @runner_factory.call(
124
130
  workstream[:path],
125
131
  options[:mode] || :execute,
126
132
  options
@@ -0,0 +1,334 @@
1
+ # AIDP Skills System
2
+
3
+ ## Overview
4
+
5
+ Skills define **WHO** the agent is (persona, expertise, capabilities), separate from templates/procedures which define **WHAT** task to execute.
6
+
7
+ This separation allows for:
8
+
9
+ - Reusable personas across multiple tasks
10
+ - Provider-agnostic skill definitions
11
+ - Clear distinction between agent identity and task execution
12
+ - Easier customization and overriding of agent behaviors
13
+
14
+ ## Skill Structure
15
+
16
+ Each skill is a directory containing a `SKILL.md` file:
17
+
18
+ ```text
19
+ skills/
20
+ └── repository_analyst/
21
+ └── SKILL.md
22
+ ```
23
+
24
+ ### SKILL.md Format
25
+
26
+ Skills use YAML frontmatter for metadata and markdown for content:
27
+
28
+ ```markdown
29
+ ---
30
+ id: repository_analyst
31
+ name: Repository Analyst
32
+ description: Expert in version control analysis and code evolution patterns
33
+ version: 1.0.0
34
+ expertise:
35
+ - version control system analysis (Git, SVN, etc.)
36
+ - code churn analysis and hotspots identification
37
+ keywords:
38
+ - git
39
+ - metrics
40
+ - hotspots
41
+ when_to_use:
42
+ - Analyzing repository history
43
+ - Identifying technical debt through metrics
44
+ when_not_to_use:
45
+ - Writing new code
46
+ - Debugging runtime issues
47
+ compatible_providers:
48
+ - anthropic
49
+ - openai
50
+ - cursor
51
+ ---
52
+
53
+ # Repository Analyst
54
+
55
+ You are a **Repository Analyst**, an expert in version control analysis...
56
+
57
+ ## Your Core Capabilities
58
+
59
+ ### Version Control Analysis
60
+ - Analyze commit history...
61
+
62
+ ## Analysis Philosophy
63
+
64
+ **Data-Driven**: Base all recommendations on actual repository metrics...
65
+ ```
66
+
67
+ ## Required Frontmatter Fields
68
+
69
+ | Field | Type | Description |
70
+ |-------|------|-------------|
71
+ | `id` | String | Unique identifier (lowercase, alphanumeric, underscores only) |
72
+ | `name` | String | Human-readable name |
73
+ | `description` | String | Brief one-line description |
74
+ | `version` | String | Semantic version (X.Y.Z format) |
75
+
76
+ ## Optional Frontmatter Fields
77
+
78
+ | Field | Type | Description |
79
+ |-------|------|-------------|
80
+ | `expertise` | Array | List of expertise areas |
81
+ | `keywords` | Array | Search/filter keywords |
82
+ | `when_to_use` | Array | Guidance for when to use this skill |
83
+ | `when_not_to_use` | Array | Guidance for when NOT to use this skill |
84
+ | `compatible_providers` | Array | Compatible provider names (empty = all) |
85
+
86
+ ## Skill Locations
87
+
88
+ ### Template Skills
89
+
90
+ Located in `templates/skills/` in the AIDP gem. These are read-only templates installed with the AIDP gem and cover common use cases; they cannot be modified directly in your project.
91
+
92
+ - **repository_analyst**: Version control and code evolution analysis
93
+ - **product_strategist**: Product planning and requirements gathering
94
+ - **architecture_analyst**: Architecture analysis and pattern identification
95
+ - **test_analyzer**: Test suite analysis and quality assessment
96
+
97
+ ### Project Skills
98
+
99
+ Located in `.aidp/skills/` for project-specific skills:
100
+
101
+ ```text
102
+ .aidp/
103
+ └── skills/
104
+ └── my_custom_skill/
105
+ └── SKILL.md
106
+ ```
107
+
108
+ Project skills with matching IDs override template skills.
109
+
110
+ ## Using Skills
111
+
112
+ ### In Step Specifications
113
+
114
+ Reference skills in step specs (e.g., [analyze/steps.rb](lib/aidp/analyze/steps.rb#L6-L60)):
115
+
116
+ ```ruby
117
+ SPEC = {
118
+ "01_REPOSITORY_ANALYSIS" => {
119
+ "skill" => "repository_analyst",
120
+ "templates" => ["analysis/analyze_repository.md"],
121
+ "description" => "Repository mining",
122
+ "outs" => ["docs/analysis/repository_analysis.md"],
123
+ "gate" => false
124
+ }
125
+ }
126
+ ```
127
+
128
+ ### Programmatic Access
129
+
130
+ ```ruby
131
+ # Load skills registry
132
+ registry = Aidp::Skills::Registry.new(project_dir: Dir.pwd)
133
+ registry.load_skills
134
+
135
+ # Find a skill
136
+ skill = registry.find("repository_analyst")
137
+
138
+ # Search skills
139
+ matching_skills = registry.search("git")
140
+
141
+ # Filter by keyword
142
+ analysis_skills = registry.by_keyword("analysis")
143
+
144
+ # Check provider compatibility
145
+ compatible = registry.compatible_with("anthropic")
146
+ ```
147
+
148
+ ### Composing with Templates
149
+
150
+ Skills are automatically composed with templates by the runner:
151
+
152
+ ```ruby
153
+ # In runner
154
+ skill = skills_registry.find(step_spec["skill"])
155
+ template = File.read(template_path)
156
+
157
+ # Compose skill + template
158
+ composed_prompt = @skills_composer.compose(
159
+ skill: skill,
160
+ template: template,
161
+ options: { variable: "value" }
162
+ )
163
+ ```
164
+
165
+ The composition structure is:
166
+
167
+ ```text
168
+ 1. Skill content (persona, expertise, philosophy)
169
+ 2. Separator (---)
170
+ 3. "# Current Task" header
171
+ 4. Template content (task-specific instructions)
172
+ ```
173
+
174
+ ## Configuration
175
+
176
+ Configure skills in `.aidp/aidp.yml`:
177
+
178
+ ```yaml
179
+ skills:
180
+ search_paths: [] # Additional skill search paths (optional)
181
+ default_provider_filter: true # Filter by provider compatibility
182
+ enable_custom_skills: true # Enable custom skill overrides
183
+ ```
184
+
185
+ ## Provider Compatibility
186
+
187
+ Skills can declare compatible providers in frontmatter:
188
+
189
+ ```yaml
190
+ compatible_providers:
191
+ - anthropic
192
+ - openai
193
+ ```
194
+
195
+ - Empty list = compatible with all providers
196
+ - Registry filters skills by provider when initialized
197
+ - Incompatible skills are skipped during loading
198
+
199
+ ## Best Practices
200
+
201
+ ### Skill Design
202
+
203
+ 1. **Focus on WHO, not WHAT**: Skills define agent identity, not task steps
204
+ 2. **Be specific**: Clearly describe expertise areas and capabilities
205
+ 3. **Provide guidance**: Use `when_to_use` and `when_not_to_use` to help with selection
206
+ 4. **Version carefully**: Use semantic versioning for tracking changes
207
+ 5. **Test compatibility**: Verify skills work with intended providers
208
+
209
+ ### Naming Conventions
210
+
211
+ - **ID**: `lowercase_with_underscores` (e.g., `repository_analyst`)
212
+ - **Name**: `Title Case` (e.g., `Repository Analyst`)
213
+ - **Files**: Always name the file `SKILL.md` (uppercase)
214
+
215
+ ### Content Guidelines
216
+
217
+ From the [LLM_STYLE_GUIDE](../docs/LLM_STYLE_GUIDE.md#L1-L202):
218
+
219
+ - Use clear, professional language
220
+ - Organize with markdown headers
221
+ - Bullet points for lists of capabilities
222
+ - Explain philosophy and approach
223
+ - Provide concrete examples when helpful
224
+
225
+ ## Creating a New Skill
226
+
227
+ 1. **Create directory structure**:
228
+
229
+ ```bash
230
+ mkdir -p skills/my_skill
231
+ ```
232
+
233
+ 2. **Create SKILL.md**:
234
+
235
+ ```bash
236
+ touch skills/my_skill/SKILL.md
237
+ ```
238
+
239
+ 3. **Add frontmatter and content**:
240
+
241
+ ```markdown
242
+ ---
243
+ id: my_skill
244
+ name: My Skill Name
245
+ description: Brief description
246
+ version: 1.0.0
247
+ expertise:
248
+ - Area 1
249
+ - Area 2
250
+ keywords:
251
+ - keyword1
252
+ when_to_use:
253
+ - Situation 1
254
+ when_not_to_use:
255
+ - Situation 2
256
+ compatible_providers:
257
+ - anthropic
258
+ ---
259
+
260
+ # My Skill Name
261
+
262
+ You are a **My Skill Name**, an expert in...
263
+ ```
264
+
265
+ 4. **Reference in steps**:
266
+
267
+ ```ruby
268
+ "MY_STEP" => {
269
+ "skill" => "my_skill",
270
+ "templates" => ["path/to/template.md"],
271
+ ...
272
+ }
273
+ ```
274
+
275
+ ## Architecture
276
+
277
+ ### Core Components
278
+
279
+ - **[Skill](lib/aidp/skills/skill.rb#L1-L187)**: Model representing a skill
280
+ - **[Loader](lib/aidp/skills/loader.rb#L1-L179)**: Parses SKILL.md files
281
+ - **[Registry](lib/aidp/skills/registry.rb#L1-L213)**: Manages available skills
282
+ - **[Composer](lib/aidp/skills/composer.rb#L1-L162)**: Combines skills with templates
283
+
284
+ ### Integration Points
285
+
286
+ - **[Analyze Runner](lib/aidp/analyze/runner.rb#L198-L236)**: Uses skills in analysis mode
287
+ - **[Execute Runner](lib/aidp/execute/runner.rb#L320-L355)**: Uses skills in execution mode
288
+ - **[Config](lib/aidp/config.rb#L166-L170)**: Skills configuration support
289
+
290
+ ## Future Enhancements
291
+
292
+ Planned for future versions (out of scope for v1):
293
+
294
+ - **Skill Inheritance**: Skills extending other skills
295
+ - **Skill Composition**: Combining multiple skills for complex tasks
296
+ - **AI-Powered Selection**: Automatically selecting best skill for a task
297
+ - **Skill Marketplace**: Sharing skills across teams/organizations
298
+ - **Dynamic Generation**: Creating skills from examples
299
+ - **Execution Validation**: Checking if output matches skill expectations
300
+
301
+ ## Related Documentation
302
+
303
+ - [PRD: Skills System](../docs/prd_skills_system.md) - Product requirements and architecture
304
+ - [LLM Style Guide](../docs/LLM_STYLE_GUIDE.md) - Coding standards for skills content
305
+ - [Issue #148](https://github.com/viamin/aidp/issues/148) - Original feature request
306
+
307
+ ## Troubleshooting
308
+
309
+ ### Skill Not Found
310
+
311
+ If a skill is referenced but not found:
312
+
313
+ 1. Check the skill ID matches exactly (case-sensitive in SPEC, but lowercase in file)
314
+ 2. Verify the SKILL.md file exists in the correct directory
315
+ 3. Check for YAML syntax errors in frontmatter
316
+ 4. Review logs for loading errors
317
+
318
+ ### Provider Compatibility Issues
319
+
320
+ If skills aren't loading for a provider:
321
+
322
+ 1. Check `compatible_providers` in frontmatter
323
+ 2. Verify provider name matches exactly
324
+ 3. Check `default_provider_filter` in config
325
+ 4. Review registry initialization logs
326
+
327
+ ### Validation Errors
328
+
329
+ Common validation errors:
330
+
331
+ - **"id must be lowercase"**: Use only lowercase letters, numbers, underscores
332
+ - **"version must be in format X.Y.Z"**: Use semantic versioning (e.g., "1.0.0")
333
+ - **"YAML frontmatter missing"**: Ensure `---` delimiters are present
334
+ - **Missing required field**: Add required frontmatter fields (id, name, description, version)