Skip to main content

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    #[must_use]
61    pub const fn name(self) -> &'static str {
62        match self {
63            Self::FeatureSpec => "feature-spec",
64            Self::BugFix => "bug-fix",
65            Self::Refactor => "refactor",
66            Self::Test => "test",
67            Self::Docs => "docs",
68            Self::Quick => "quick",
69            Self::PerformanceOptimization => "performance-optimization",
70            Self::SecurityAudit => "security-audit",
71            Self::ApiIntegration => "api-integration",
72            Self::DatabaseMigration => "database-migration",
73            Self::DependencyUpdate => "dependency-update",
74            Self::CliTool => "cli-tool",
75            Self::WebApi => "web-api",
76            Self::DataPipeline => "data-pipeline",
77            Self::UiComponent => "ui-component",
78            Self::CodeReview => "code-review",
79            Self::DebugTriage => "debug-triage",
80            Self::Release => "release",
81            Self::TechDebt => "tech-debt",
82            Self::Onboarding => "onboarding",
83        }
84    }
85
86    /// Returns a short description of this template.
87    #[must_use]
88    pub const fn description(self) -> &'static str {
89        match self {
90            Self::FeatureSpec => "Comprehensive product specification with questions to consider and code quality standards",
91            Self::BugFix => "Bug fix template with investigation guidance and testing requirements",
92            Self::Refactor => "Code refactoring template with behavior preservation emphasis",
93            Self::Test => "Test writing template with edge case considerations",
94            Self::Docs => "Documentation update template with completeness checklist",
95            Self::Quick => "Quick/small change template (minimal)",
96            Self::PerformanceOptimization => "Performance optimization template with benchmarking and profiling guidance",
97            Self::SecurityAudit => "Security audit template covering OWASP Top 10 and vulnerability remediation",
98            Self::ApiIntegration => "API integration template with error handling, retry logic, and resilience patterns",
99            Self::DatabaseMigration => "Database migration template with zero-downtime strategies and rollback plans",
100            Self::DependencyUpdate => "Dependency update template with migration guides and breaking change handling",
101            Self::CliTool => "CLI tool development template with argument parsing, completion, and error handling",
102            Self::WebApi => "Web API development template with REST design, error handling, and security considerations",
103            Self::DataPipeline => "Data pipeline template with ETL processing, reliability, and monitoring guidance",
104            Self::UiComponent => "UI component template with accessibility, responsive design, and user experience",
105            Self::CodeReview => "Code review template for structured pull request feedback",
106            Self::DebugTriage => "Debug triage template for systematic issue investigation and diagnosis",
107            Self::Release => "Release preparation template with versioning, changelog, and deployment checklist",
108            Self::TechDebt => "Technical debt refactoring template with prioritization and planning guidance",
109            Self::Onboarding => "Onboarding template for learning new codebases efficiently",
110        }
111    }
112
113    /// Returns the embedded template content.
114    #[must_use]
115    pub const fn content(self) -> &'static str {
116        match self {
117            Self::FeatureSpec => {
118                include_str!("../../templates/prompts/feature-spec.md")
119            }
120            Self::BugFix => {
121                include_str!("../../templates/prompts/bug-fix.md")
122            }
123            Self::Refactor => {
124                include_str!("../../templates/prompts/refactor.md")
125            }
126            Self::Test => {
127                include_str!("../../templates/prompts/test.md")
128            }
129            Self::Docs => {
130                include_str!("../../templates/prompts/docs.md")
131            }
132            Self::Quick => {
133                include_str!("../../templates/prompts/quick.md")
134            }
135            Self::PerformanceOptimization => {
136                include_str!("../../templates/prompts/performance-optimization.md")
137            }
138            Self::SecurityAudit => {
139                include_str!("../../templates/prompts/security-audit.md")
140            }
141            Self::ApiIntegration => {
142                include_str!("../../templates/prompts/api-integration.md")
143            }
144            Self::DatabaseMigration => {
145                include_str!("../../templates/prompts/database-migration.md")
146            }
147            Self::DependencyUpdate => {
148                include_str!("../../templates/prompts/dependency-update.md")
149            }
150            Self::CliTool => {
151                include_str!("../../templates/prompts/cli-tool.md")
152            }
153            Self::WebApi => {
154                include_str!("../../templates/prompts/web-api.md")
155            }
156            Self::DataPipeline => {
157                include_str!("../../templates/prompts/data-pipeline.md")
158            }
159            Self::UiComponent => {
160                include_str!("../../templates/prompts/ui-component.md")
161            }
162            Self::CodeReview => {
163                include_str!("../../templates/prompts/code-review.md")
164            }
165            Self::DebugTriage => {
166                include_str!("../../templates/prompts/debug-triage.md")
167            }
168            Self::Release => {
169                include_str!("../../templates/prompts/release.md")
170            }
171            Self::TechDebt => {
172                include_str!("../../templates/prompts/tech-debt.md")
173            }
174            Self::Onboarding => {
175                include_str!("../../templates/prompts/onboarding.md")
176            }
177        }
178    }
179}
180
181impl fmt::Display for PromptTemplate {
182    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183        write!(f, "{}", self.name())
184    }
185}
186
187/// All available prompt templates.
188pub const ALL_TEMPLATES: [PromptTemplate; 20] = [
189    PromptTemplate::FeatureSpec,
190    PromptTemplate::BugFix,
191    PromptTemplate::Refactor,
192    PromptTemplate::Test,
193    PromptTemplate::Docs,
194    PromptTemplate::Quick,
195    PromptTemplate::PerformanceOptimization,
196    PromptTemplate::SecurityAudit,
197    PromptTemplate::ApiIntegration,
198    PromptTemplate::DatabaseMigration,
199    PromptTemplate::DependencyUpdate,
200    PromptTemplate::CliTool,
201    PromptTemplate::WebApi,
202    PromptTemplate::DataPipeline,
203    PromptTemplate::UiComponent,
204    PromptTemplate::CodeReview,
205    PromptTemplate::DebugTriage,
206    PromptTemplate::Release,
207    PromptTemplate::TechDebt,
208    PromptTemplate::Onboarding,
209];
210
211/// Get a template by name.
212///
213/// # Arguments
214///
215/// * `name` - The template name (e.g., "feature-spec", "bug-fix")
216///
217/// # Returns
218///
219/// * `Some(PromptTemplate)` - The template if found
220/// * `None` - If no template matches the name
221#[must_use]
222pub fn get_template(name: &str) -> Option<PromptTemplate> {
223    match name {
224        "feature-spec" => Some(PromptTemplate::FeatureSpec),
225        "bug-fix" => Some(PromptTemplate::BugFix),
226        "refactor" => Some(PromptTemplate::Refactor),
227        "test" => Some(PromptTemplate::Test),
228        "docs" => Some(PromptTemplate::Docs),
229        "quick" => Some(PromptTemplate::Quick),
230        "performance-optimization" => Some(PromptTemplate::PerformanceOptimization),
231        "security-audit" => Some(PromptTemplate::SecurityAudit),
232        "api-integration" => Some(PromptTemplate::ApiIntegration),
233        "database-migration" => Some(PromptTemplate::DatabaseMigration),
234        "dependency-update" => Some(PromptTemplate::DependencyUpdate),
235        "cli-tool" => Some(PromptTemplate::CliTool),
236        "web-api" => Some(PromptTemplate::WebApi),
237        "data-pipeline" => Some(PromptTemplate::DataPipeline),
238        "ui-component" => Some(PromptTemplate::UiComponent),
239        "code-review" => Some(PromptTemplate::CodeReview),
240        "debug-triage" => Some(PromptTemplate::DebugTriage),
241        "release" => Some(PromptTemplate::Release),
242        "tech-debt" => Some(PromptTemplate::TechDebt),
243        "onboarding" => Some(PromptTemplate::Onboarding),
244        _ => None,
245    }
246}
247
248/// List all available templates with their descriptions.
249///
250/// Returns a vector of (name, description) tuples.
251#[must_use]
252pub fn list_templates() -> Vec<(&'static str, &'static str)> {
253    vec![
254        (
255            PromptTemplate::FeatureSpec.name(),
256            PromptTemplate::FeatureSpec.description(),
257        ),
258        (
259            PromptTemplate::BugFix.name(),
260            PromptTemplate::BugFix.description(),
261        ),
262        (
263            PromptTemplate::Refactor.name(),
264            PromptTemplate::Refactor.description(),
265        ),
266        (
267            PromptTemplate::Test.name(),
268            PromptTemplate::Test.description(),
269        ),
270        (
271            PromptTemplate::Docs.name(),
272            PromptTemplate::Docs.description(),
273        ),
274        (
275            PromptTemplate::Quick.name(),
276            PromptTemplate::Quick.description(),
277        ),
278        (
279            PromptTemplate::PerformanceOptimization.name(),
280            PromptTemplate::PerformanceOptimization.description(),
281        ),
282        (
283            PromptTemplate::SecurityAudit.name(),
284            PromptTemplate::SecurityAudit.description(),
285        ),
286        (
287            PromptTemplate::ApiIntegration.name(),
288            PromptTemplate::ApiIntegration.description(),
289        ),
290        (
291            PromptTemplate::DatabaseMigration.name(),
292            PromptTemplate::DatabaseMigration.description(),
293        ),
294        (
295            PromptTemplate::DependencyUpdate.name(),
296            PromptTemplate::DependencyUpdate.description(),
297        ),
298        (
299            PromptTemplate::CliTool.name(),
300            PromptTemplate::CliTool.description(),
301        ),
302        (
303            PromptTemplate::WebApi.name(),
304            PromptTemplate::WebApi.description(),
305        ),
306        (
307            PromptTemplate::DataPipeline.name(),
308            PromptTemplate::DataPipeline.description(),
309        ),
310        (
311            PromptTemplate::UiComponent.name(),
312            PromptTemplate::UiComponent.description(),
313        ),
314        (
315            PromptTemplate::CodeReview.name(),
316            PromptTemplate::CodeReview.description(),
317        ),
318        (
319            PromptTemplate::DebugTriage.name(),
320            PromptTemplate::DebugTriage.description(),
321        ),
322        (
323            PromptTemplate::Release.name(),
324            PromptTemplate::Release.description(),
325        ),
326        (
327            PromptTemplate::TechDebt.name(),
328            PromptTemplate::TechDebt.description(),
329        ),
330        (
331            PromptTemplate::Onboarding.name(),
332            PromptTemplate::Onboarding.description(),
333        ),
334    ]
335}
336
337#[cfg(test)]
338mod tests {
339    use super::*;
340
341    #[test]
342    fn test_template_names() {
343        assert_eq!(PromptTemplate::FeatureSpec.name(), "feature-spec");
344        assert_eq!(PromptTemplate::BugFix.name(), "bug-fix");
345        assert_eq!(PromptTemplate::Refactor.name(), "refactor");
346        assert_eq!(PromptTemplate::Test.name(), "test");
347        assert_eq!(PromptTemplate::Docs.name(), "docs");
348        assert_eq!(PromptTemplate::Quick.name(), "quick");
349        assert_eq!(
350            PromptTemplate::PerformanceOptimization.name(),
351            "performance-optimization"
352        );
353        assert_eq!(PromptTemplate::SecurityAudit.name(), "security-audit");
354        assert_eq!(PromptTemplate::ApiIntegration.name(), "api-integration");
355        assert_eq!(
356            PromptTemplate::DatabaseMigration.name(),
357            "database-migration"
358        );
359        assert_eq!(PromptTemplate::DependencyUpdate.name(), "dependency-update");
360        assert_eq!(PromptTemplate::CliTool.name(), "cli-tool");
361        assert_eq!(PromptTemplate::WebApi.name(), "web-api");
362        assert_eq!(PromptTemplate::DataPipeline.name(), "data-pipeline");
363        assert_eq!(PromptTemplate::UiComponent.name(), "ui-component");
364        assert_eq!(PromptTemplate::CodeReview.name(), "code-review");
365        assert_eq!(PromptTemplate::DebugTriage.name(), "debug-triage");
366        assert_eq!(PromptTemplate::Release.name(), "release");
367        assert_eq!(PromptTemplate::TechDebt.name(), "tech-debt");
368        assert_eq!(PromptTemplate::Onboarding.name(), "onboarding");
369    }
370
371    #[test]
372    fn test_template_descriptions() {
373        assert!(!PromptTemplate::FeatureSpec.description().is_empty());
374        assert!(!PromptTemplate::BugFix.description().is_empty());
375        assert!(!PromptTemplate::Refactor.description().is_empty());
376        assert!(!PromptTemplate::Test.description().is_empty());
377        assert!(!PromptTemplate::Docs.description().is_empty());
378        assert!(!PromptTemplate::Quick.description().is_empty());
379        assert!(!PromptTemplate::PerformanceOptimization
380            .description()
381            .is_empty());
382        assert!(!PromptTemplate::SecurityAudit.description().is_empty());
383        assert!(!PromptTemplate::ApiIntegration.description().is_empty());
384        assert!(!PromptTemplate::DatabaseMigration.description().is_empty());
385        assert!(!PromptTemplate::DependencyUpdate.description().is_empty());
386        assert!(!PromptTemplate::CliTool.description().is_empty());
387        assert!(!PromptTemplate::WebApi.description().is_empty());
388        assert!(!PromptTemplate::DataPipeline.description().is_empty());
389        assert!(!PromptTemplate::UiComponent.description().is_empty());
390        assert!(!PromptTemplate::CodeReview.description().is_empty());
391        assert!(!PromptTemplate::DebugTriage.description().is_empty());
392        assert!(!PromptTemplate::Release.description().is_empty());
393        assert!(!PromptTemplate::TechDebt.description().is_empty());
394        assert!(!PromptTemplate::Onboarding.description().is_empty());
395    }
396
397    #[test]
398    fn test_get_template() {
399        assert_eq!(
400            get_template("feature-spec"),
401            Some(PromptTemplate::FeatureSpec)
402        );
403        assert_eq!(get_template("bug-fix"), Some(PromptTemplate::BugFix));
404        assert_eq!(
405            get_template("performance-optimization"),
406            Some(PromptTemplate::PerformanceOptimization)
407        );
408        assert_eq!(
409            get_template("security-audit"),
410            Some(PromptTemplate::SecurityAudit)
411        );
412        assert_eq!(
413            get_template("api-integration"),
414            Some(PromptTemplate::ApiIntegration)
415        );
416        assert_eq!(
417            get_template("database-migration"),
418            Some(PromptTemplate::DatabaseMigration)
419        );
420        assert_eq!(
421            get_template("dependency-update"),
422            Some(PromptTemplate::DependencyUpdate)
423        );
424        assert_eq!(get_template("cli-tool"), Some(PromptTemplate::CliTool));
425        assert_eq!(get_template("web-api"), Some(PromptTemplate::WebApi));
426        assert_eq!(
427            get_template("data-pipeline"),
428            Some(PromptTemplate::DataPipeline)
429        );
430        assert_eq!(
431            get_template("ui-component"),
432            Some(PromptTemplate::UiComponent)
433        );
434        assert_eq!(
435            get_template("code-review"),
436            Some(PromptTemplate::CodeReview)
437        );
438        assert_eq!(
439            get_template("debug-triage"),
440            Some(PromptTemplate::DebugTriage)
441        );
442        assert_eq!(get_template("release"), Some(PromptTemplate::Release));
443        assert_eq!(get_template("tech-debt"), Some(PromptTemplate::TechDebt));
444        assert_eq!(get_template("onboarding"), Some(PromptTemplate::Onboarding));
445        assert_eq!(get_template("nonexistent"), None);
446    }
447
448    #[test]
449    fn test_list_templates() {
450        let templates = list_templates();
451        assert_eq!(templates.len(), 20);
452        assert!(templates.iter().any(|(name, _)| name == &"feature-spec"));
453        assert!(templates.iter().any(|(name, _)| name == &"bug-fix"));
454        assert!(templates
455            .iter()
456            .any(|(name, _)| name == &"performance-optimization"));
457        assert!(templates.iter().any(|(name, _)| name == &"security-audit"));
458        assert!(templates.iter().any(|(name, _)| name == &"api-integration"));
459        assert!(templates
460            .iter()
461            .any(|(name, _)| name == &"database-migration"));
462        assert!(templates
463            .iter()
464            .any(|(name, _)| name == &"dependency-update"));
465        assert!(templates.iter().any(|(name, _)| name == &"cli-tool"));
466        assert!(templates.iter().any(|(name, _)| name == &"web-api"));
467        assert!(templates.iter().any(|(name, _)| name == &"data-pipeline"));
468        assert!(templates.iter().any(|(name, _)| name == &"ui-component"));
469        assert!(templates.iter().any(|(name, _)| name == &"code-review"));
470        assert!(templates.iter().any(|(name, _)| name == &"debug-triage"));
471        assert!(templates.iter().any(|(name, _)| name == &"release"));
472        assert!(templates.iter().any(|(name, _)| name == &"tech-debt"));
473        assert!(templates.iter().any(|(name, _)| name == &"onboarding"));
474    }
475
476    #[test]
477    fn test_template_content_has_goal() {
478        ALL_TEMPLATES.iter().for_each(|template| {
479            let content = template.content();
480            assert!(
481                content.contains("## Goal"),
482                "Template {} missing Goal section",
483                template.name()
484            );
485        });
486    }
487
488    #[test]
489    fn test_template_content_has_acceptance() {
490        ALL_TEMPLATES.iter().for_each(|template| {
491            let content = template.content();
492            assert!(
493                content.contains("## Acceptance") || content.contains("## Acceptance Checks"),
494                "Template {} missing Acceptance section",
495                template.name()
496            );
497        });
498    }
499}