ralph_workflow/templates/
mod.rs

1//! Prompt template management module.
2//!
3//! This module provides a collection of PROMPT.md templates for different
4//! task types (feature specifications, bug fixes, refactoring, etc.).
5//!
6//! Templates are embedded at compile time using `include_str!` and can be
7//! accessed via the `get_template_content()` function.
8
9use std::fmt;
10
11/// Available prompt template types.
12///
13/// Each variant represents a different template for a specific use case.
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum PromptTemplate {
16    /// Comprehensive product specification template
17    FeatureSpec,
18    /// Concise bug fix template
19    BugFix,
20    /// Code refactoring template
21    Refactor,
22    /// Test writing template
23    Test,
24    /// Documentation update template
25    Docs,
26    /// Quick/small change template
27    Quick,
28    /// Performance optimization template
29    PerformanceOptimization,
30    /// Security audit template
31    SecurityAudit,
32    /// API integration template
33    ApiIntegration,
34    /// Database migration template
35    DatabaseMigration,
36    /// Dependency update template
37    DependencyUpdate,
38    /// CLI tool development template
39    CliTool,
40    /// Web API development template
41    WebApi,
42    /// Data pipeline template
43    DataPipeline,
44    /// UI component template
45    UiComponent,
46    /// Code review template
47    CodeReview,
48    /// Debug triage template
49    DebugTriage,
50    /// Release preparation template
51    Release,
52    /// Technical debt refactoring template
53    TechDebt,
54    /// Onboarding template
55    Onboarding,
56}
57
58impl PromptTemplate {
59    /// Returns the name/key for this template (used for CLI arguments).
60    pub const fn name(self) -> &'static str {
61        match self {
62            Self::FeatureSpec => "feature-spec",
63            Self::BugFix => "bug-fix",
64            Self::Refactor => "refactor",
65            Self::Test => "test",
66            Self::Docs => "docs",
67            Self::Quick => "quick",
68            Self::PerformanceOptimization => "performance-optimization",
69            Self::SecurityAudit => "security-audit",
70            Self::ApiIntegration => "api-integration",
71            Self::DatabaseMigration => "database-migration",
72            Self::DependencyUpdate => "dependency-update",
73            Self::CliTool => "cli-tool",
74            Self::WebApi => "web-api",
75            Self::DataPipeline => "data-pipeline",
76            Self::UiComponent => "ui-component",
77            Self::CodeReview => "code-review",
78            Self::DebugTriage => "debug-triage",
79            Self::Release => "release",
80            Self::TechDebt => "tech-debt",
81            Self::Onboarding => "onboarding",
82        }
83    }
84
85    /// Returns a short description of this template.
86    pub const fn description(self) -> &'static str {
87        match self {
88            Self::FeatureSpec => "Comprehensive product specification with questions to consider and code quality standards",
89            Self::BugFix => "Bug fix template with investigation guidance and testing requirements",
90            Self::Refactor => "Code refactoring template with behavior preservation emphasis",
91            Self::Test => "Test writing template with edge case considerations",
92            Self::Docs => "Documentation update template with completeness checklist",
93            Self::Quick => "Quick/small change template (minimal)",
94            Self::PerformanceOptimization => "Performance optimization template with benchmarking and profiling guidance",
95            Self::SecurityAudit => "Security audit template covering OWASP Top 10 and vulnerability remediation",
96            Self::ApiIntegration => "API integration template with error handling, retry logic, and resilience patterns",
97            Self::DatabaseMigration => "Database migration template with zero-downtime strategies and rollback plans",
98            Self::DependencyUpdate => "Dependency update template with migration guides and breaking change handling",
99            Self::CliTool => "CLI tool development template with argument parsing, completion, and error handling",
100            Self::WebApi => "Web API development template with REST design, error handling, and security considerations",
101            Self::DataPipeline => "Data pipeline template with ETL processing, reliability, and monitoring guidance",
102            Self::UiComponent => "UI component template with accessibility, responsive design, and user experience",
103            Self::CodeReview => "Code review template for structured pull request feedback",
104            Self::DebugTriage => "Debug triage template for systematic issue investigation and diagnosis",
105            Self::Release => "Release preparation template with versioning, changelog, and deployment checklist",
106            Self::TechDebt => "Technical debt refactoring template with prioritization and planning guidance",
107            Self::Onboarding => "Onboarding template for learning new codebases efficiently",
108        }
109    }
110
111    /// Returns the embedded template content.
112    pub const fn content(self) -> &'static str {
113        match self {
114            Self::FeatureSpec => {
115                include_str!("../../templates/prompts/feature-spec.md")
116            }
117            Self::BugFix => {
118                include_str!("../../templates/prompts/bug-fix.md")
119            }
120            Self::Refactor => {
121                include_str!("../../templates/prompts/refactor.md")
122            }
123            Self::Test => {
124                include_str!("../../templates/prompts/test.md")
125            }
126            Self::Docs => {
127                include_str!("../../templates/prompts/docs.md")
128            }
129            Self::Quick => {
130                include_str!("../../templates/prompts/quick.md")
131            }
132            Self::PerformanceOptimization => {
133                include_str!("../../templates/prompts/performance-optimization.md")
134            }
135            Self::SecurityAudit => {
136                include_str!("../../templates/prompts/security-audit.md")
137            }
138            Self::ApiIntegration => {
139                include_str!("../../templates/prompts/api-integration.md")
140            }
141            Self::DatabaseMigration => {
142                include_str!("../../templates/prompts/database-migration.md")
143            }
144            Self::DependencyUpdate => {
145                include_str!("../../templates/prompts/dependency-update.md")
146            }
147            Self::CliTool => {
148                include_str!("../../templates/prompts/cli-tool.md")
149            }
150            Self::WebApi => {
151                include_str!("../../templates/prompts/web-api.md")
152            }
153            Self::DataPipeline => {
154                include_str!("../../templates/prompts/data-pipeline.md")
155            }
156            Self::UiComponent => {
157                include_str!("../../templates/prompts/ui-component.md")
158            }
159            Self::CodeReview => {
160                include_str!("../../templates/prompts/code-review.md")
161            }
162            Self::DebugTriage => {
163                include_str!("../../templates/prompts/debug-triage.md")
164            }
165            Self::Release => {
166                include_str!("../../templates/prompts/release.md")
167            }
168            Self::TechDebt => {
169                include_str!("../../templates/prompts/tech-debt.md")
170            }
171            Self::Onboarding => {
172                include_str!("../../templates/prompts/onboarding.md")
173            }
174        }
175    }
176}
177
178impl fmt::Display for PromptTemplate {
179    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180        write!(f, "{}", self.name())
181    }
182}
183
184/// All available prompt templates.
185pub const ALL_TEMPLATES: [PromptTemplate; 20] = [
186    PromptTemplate::FeatureSpec,
187    PromptTemplate::BugFix,
188    PromptTemplate::Refactor,
189    PromptTemplate::Test,
190    PromptTemplate::Docs,
191    PromptTemplate::Quick,
192    PromptTemplate::PerformanceOptimization,
193    PromptTemplate::SecurityAudit,
194    PromptTemplate::ApiIntegration,
195    PromptTemplate::DatabaseMigration,
196    PromptTemplate::DependencyUpdate,
197    PromptTemplate::CliTool,
198    PromptTemplate::WebApi,
199    PromptTemplate::DataPipeline,
200    PromptTemplate::UiComponent,
201    PromptTemplate::CodeReview,
202    PromptTemplate::DebugTriage,
203    PromptTemplate::Release,
204    PromptTemplate::TechDebt,
205    PromptTemplate::Onboarding,
206];
207
208/// Get a template by name.
209///
210/// # Arguments
211///
212/// * `name` - The template name (e.g., "feature-spec", "bug-fix")
213///
214/// # Returns
215///
216/// * `Some(PromptTemplate)` - The template if found
217/// * `None` - If no template matches the name
218pub fn get_template(name: &str) -> Option<PromptTemplate> {
219    ALL_TEMPLATES.iter().find(|t| t.name() == name).copied()
220}
221
222/// List all available templates with their descriptions.
223///
224/// Returns a vector of (name, description) tuples.
225pub fn list_templates() -> Vec<(&'static str, &'static str)> {
226    ALL_TEMPLATES
227        .iter()
228        .map(|t| (t.name(), t.description()))
229        .collect()
230}
231
232#[cfg(test)]
233mod tests {
234    use super::*;
235
236    #[test]
237    fn test_template_names() {
238        assert_eq!(PromptTemplate::FeatureSpec.name(), "feature-spec");
239        assert_eq!(PromptTemplate::BugFix.name(), "bug-fix");
240        assert_eq!(PromptTemplate::Refactor.name(), "refactor");
241        assert_eq!(PromptTemplate::Test.name(), "test");
242        assert_eq!(PromptTemplate::Docs.name(), "docs");
243        assert_eq!(PromptTemplate::Quick.name(), "quick");
244        assert_eq!(
245            PromptTemplate::PerformanceOptimization.name(),
246            "performance-optimization"
247        );
248        assert_eq!(PromptTemplate::SecurityAudit.name(), "security-audit");
249        assert_eq!(PromptTemplate::ApiIntegration.name(), "api-integration");
250        assert_eq!(
251            PromptTemplate::DatabaseMigration.name(),
252            "database-migration"
253        );
254        assert_eq!(PromptTemplate::DependencyUpdate.name(), "dependency-update");
255        assert_eq!(PromptTemplate::CliTool.name(), "cli-tool");
256        assert_eq!(PromptTemplate::WebApi.name(), "web-api");
257        assert_eq!(PromptTemplate::DataPipeline.name(), "data-pipeline");
258        assert_eq!(PromptTemplate::UiComponent.name(), "ui-component");
259        assert_eq!(PromptTemplate::CodeReview.name(), "code-review");
260        assert_eq!(PromptTemplate::DebugTriage.name(), "debug-triage");
261        assert_eq!(PromptTemplate::Release.name(), "release");
262        assert_eq!(PromptTemplate::TechDebt.name(), "tech-debt");
263        assert_eq!(PromptTemplate::Onboarding.name(), "onboarding");
264    }
265
266    #[test]
267    fn test_template_descriptions() {
268        assert!(!PromptTemplate::FeatureSpec.description().is_empty());
269        assert!(!PromptTemplate::BugFix.description().is_empty());
270        assert!(!PromptTemplate::Refactor.description().is_empty());
271        assert!(!PromptTemplate::Test.description().is_empty());
272        assert!(!PromptTemplate::Docs.description().is_empty());
273        assert!(!PromptTemplate::Quick.description().is_empty());
274        assert!(!PromptTemplate::PerformanceOptimization
275            .description()
276            .is_empty());
277        assert!(!PromptTemplate::SecurityAudit.description().is_empty());
278        assert!(!PromptTemplate::ApiIntegration.description().is_empty());
279        assert!(!PromptTemplate::DatabaseMigration.description().is_empty());
280        assert!(!PromptTemplate::DependencyUpdate.description().is_empty());
281        assert!(!PromptTemplate::CliTool.description().is_empty());
282        assert!(!PromptTemplate::WebApi.description().is_empty());
283        assert!(!PromptTemplate::DataPipeline.description().is_empty());
284        assert!(!PromptTemplate::UiComponent.description().is_empty());
285        assert!(!PromptTemplate::CodeReview.description().is_empty());
286        assert!(!PromptTemplate::DebugTriage.description().is_empty());
287        assert!(!PromptTemplate::Release.description().is_empty());
288        assert!(!PromptTemplate::TechDebt.description().is_empty());
289        assert!(!PromptTemplate::Onboarding.description().is_empty());
290    }
291
292    #[test]
293    fn test_get_template() {
294        assert_eq!(
295            get_template("feature-spec"),
296            Some(PromptTemplate::FeatureSpec)
297        );
298        assert_eq!(get_template("bug-fix"), Some(PromptTemplate::BugFix));
299        assert_eq!(
300            get_template("performance-optimization"),
301            Some(PromptTemplate::PerformanceOptimization)
302        );
303        assert_eq!(
304            get_template("security-audit"),
305            Some(PromptTemplate::SecurityAudit)
306        );
307        assert_eq!(
308            get_template("api-integration"),
309            Some(PromptTemplate::ApiIntegration)
310        );
311        assert_eq!(
312            get_template("database-migration"),
313            Some(PromptTemplate::DatabaseMigration)
314        );
315        assert_eq!(
316            get_template("dependency-update"),
317            Some(PromptTemplate::DependencyUpdate)
318        );
319        assert_eq!(get_template("cli-tool"), Some(PromptTemplate::CliTool));
320        assert_eq!(get_template("web-api"), Some(PromptTemplate::WebApi));
321        assert_eq!(
322            get_template("data-pipeline"),
323            Some(PromptTemplate::DataPipeline)
324        );
325        assert_eq!(
326            get_template("ui-component"),
327            Some(PromptTemplate::UiComponent)
328        );
329        assert_eq!(
330            get_template("code-review"),
331            Some(PromptTemplate::CodeReview)
332        );
333        assert_eq!(
334            get_template("debug-triage"),
335            Some(PromptTemplate::DebugTriage)
336        );
337        assert_eq!(get_template("release"), Some(PromptTemplate::Release));
338        assert_eq!(get_template("tech-debt"), Some(PromptTemplate::TechDebt));
339        assert_eq!(get_template("onboarding"), Some(PromptTemplate::Onboarding));
340        assert_eq!(get_template("nonexistent"), None);
341    }
342
343    #[test]
344    fn test_list_templates() {
345        let templates = list_templates();
346        assert_eq!(templates.len(), 20);
347        assert!(templates.iter().any(|(name, _)| name == &"feature-spec"));
348        assert!(templates.iter().any(|(name, _)| name == &"bug-fix"));
349        assert!(templates
350            .iter()
351            .any(|(name, _)| name == &"performance-optimization"));
352        assert!(templates.iter().any(|(name, _)| name == &"security-audit"));
353        assert!(templates.iter().any(|(name, _)| name == &"api-integration"));
354        assert!(templates
355            .iter()
356            .any(|(name, _)| name == &"database-migration"));
357        assert!(templates
358            .iter()
359            .any(|(name, _)| name == &"dependency-update"));
360        assert!(templates.iter().any(|(name, _)| name == &"cli-tool"));
361        assert!(templates.iter().any(|(name, _)| name == &"web-api"));
362        assert!(templates.iter().any(|(name, _)| name == &"data-pipeline"));
363        assert!(templates.iter().any(|(name, _)| name == &"ui-component"));
364        assert!(templates.iter().any(|(name, _)| name == &"code-review"));
365        assert!(templates.iter().any(|(name, _)| name == &"debug-triage"));
366        assert!(templates.iter().any(|(name, _)| name == &"release"));
367        assert!(templates.iter().any(|(name, _)| name == &"tech-debt"));
368        assert!(templates.iter().any(|(name, _)| name == &"onboarding"));
369    }
370
371    #[test]
372    fn test_template_content_has_goal() {
373        for template in ALL_TEMPLATES {
374            let content = template.content();
375            assert!(
376                content.contains("## Goal"),
377                "Template {} missing Goal section",
378                template.name()
379            );
380        }
381    }
382
383    #[test]
384    fn test_template_content_has_acceptance() {
385        for template in ALL_TEMPLATES {
386            let content = template.content();
387            assert!(
388                content.contains("## Acceptance") || content.contains("## Acceptance Checks"),
389                "Template {} missing Acceptance section",
390                template.name()
391            );
392        }
393    }
394}