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    ALL_TEMPLATES.iter().find(|t| t.name() == name).copied()
224}
225
226/// List all available templates with their descriptions.
227///
228/// Returns a vector of (name, description) tuples.
229#[must_use]
230pub fn list_templates() -> Vec<(&'static str, &'static str)> {
231    ALL_TEMPLATES
232        .iter()
233        .map(|t| (t.name(), t.description()))
234        .collect()
235}
236
237#[cfg(test)]
238mod tests {
239    use super::*;
240
241    #[test]
242    fn test_template_names() {
243        assert_eq!(PromptTemplate::FeatureSpec.name(), "feature-spec");
244        assert_eq!(PromptTemplate::BugFix.name(), "bug-fix");
245        assert_eq!(PromptTemplate::Refactor.name(), "refactor");
246        assert_eq!(PromptTemplate::Test.name(), "test");
247        assert_eq!(PromptTemplate::Docs.name(), "docs");
248        assert_eq!(PromptTemplate::Quick.name(), "quick");
249        assert_eq!(
250            PromptTemplate::PerformanceOptimization.name(),
251            "performance-optimization"
252        );
253        assert_eq!(PromptTemplate::SecurityAudit.name(), "security-audit");
254        assert_eq!(PromptTemplate::ApiIntegration.name(), "api-integration");
255        assert_eq!(
256            PromptTemplate::DatabaseMigration.name(),
257            "database-migration"
258        );
259        assert_eq!(PromptTemplate::DependencyUpdate.name(), "dependency-update");
260        assert_eq!(PromptTemplate::CliTool.name(), "cli-tool");
261        assert_eq!(PromptTemplate::WebApi.name(), "web-api");
262        assert_eq!(PromptTemplate::DataPipeline.name(), "data-pipeline");
263        assert_eq!(PromptTemplate::UiComponent.name(), "ui-component");
264        assert_eq!(PromptTemplate::CodeReview.name(), "code-review");
265        assert_eq!(PromptTemplate::DebugTriage.name(), "debug-triage");
266        assert_eq!(PromptTemplate::Release.name(), "release");
267        assert_eq!(PromptTemplate::TechDebt.name(), "tech-debt");
268        assert_eq!(PromptTemplate::Onboarding.name(), "onboarding");
269    }
270
271    #[test]
272    fn test_template_descriptions() {
273        assert!(!PromptTemplate::FeatureSpec.description().is_empty());
274        assert!(!PromptTemplate::BugFix.description().is_empty());
275        assert!(!PromptTemplate::Refactor.description().is_empty());
276        assert!(!PromptTemplate::Test.description().is_empty());
277        assert!(!PromptTemplate::Docs.description().is_empty());
278        assert!(!PromptTemplate::Quick.description().is_empty());
279        assert!(!PromptTemplate::PerformanceOptimization
280            .description()
281            .is_empty());
282        assert!(!PromptTemplate::SecurityAudit.description().is_empty());
283        assert!(!PromptTemplate::ApiIntegration.description().is_empty());
284        assert!(!PromptTemplate::DatabaseMigration.description().is_empty());
285        assert!(!PromptTemplate::DependencyUpdate.description().is_empty());
286        assert!(!PromptTemplate::CliTool.description().is_empty());
287        assert!(!PromptTemplate::WebApi.description().is_empty());
288        assert!(!PromptTemplate::DataPipeline.description().is_empty());
289        assert!(!PromptTemplate::UiComponent.description().is_empty());
290        assert!(!PromptTemplate::CodeReview.description().is_empty());
291        assert!(!PromptTemplate::DebugTriage.description().is_empty());
292        assert!(!PromptTemplate::Release.description().is_empty());
293        assert!(!PromptTemplate::TechDebt.description().is_empty());
294        assert!(!PromptTemplate::Onboarding.description().is_empty());
295    }
296
297    #[test]
298    fn test_get_template() {
299        assert_eq!(
300            get_template("feature-spec"),
301            Some(PromptTemplate::FeatureSpec)
302        );
303        assert_eq!(get_template("bug-fix"), Some(PromptTemplate::BugFix));
304        assert_eq!(
305            get_template("performance-optimization"),
306            Some(PromptTemplate::PerformanceOptimization)
307        );
308        assert_eq!(
309            get_template("security-audit"),
310            Some(PromptTemplate::SecurityAudit)
311        );
312        assert_eq!(
313            get_template("api-integration"),
314            Some(PromptTemplate::ApiIntegration)
315        );
316        assert_eq!(
317            get_template("database-migration"),
318            Some(PromptTemplate::DatabaseMigration)
319        );
320        assert_eq!(
321            get_template("dependency-update"),
322            Some(PromptTemplate::DependencyUpdate)
323        );
324        assert_eq!(get_template("cli-tool"), Some(PromptTemplate::CliTool));
325        assert_eq!(get_template("web-api"), Some(PromptTemplate::WebApi));
326        assert_eq!(
327            get_template("data-pipeline"),
328            Some(PromptTemplate::DataPipeline)
329        );
330        assert_eq!(
331            get_template("ui-component"),
332            Some(PromptTemplate::UiComponent)
333        );
334        assert_eq!(
335            get_template("code-review"),
336            Some(PromptTemplate::CodeReview)
337        );
338        assert_eq!(
339            get_template("debug-triage"),
340            Some(PromptTemplate::DebugTriage)
341        );
342        assert_eq!(get_template("release"), Some(PromptTemplate::Release));
343        assert_eq!(get_template("tech-debt"), Some(PromptTemplate::TechDebt));
344        assert_eq!(get_template("onboarding"), Some(PromptTemplate::Onboarding));
345        assert_eq!(get_template("nonexistent"), None);
346    }
347
348    #[test]
349    fn test_list_templates() {
350        let templates = list_templates();
351        assert_eq!(templates.len(), 20);
352        assert!(templates.iter().any(|(name, _)| name == &"feature-spec"));
353        assert!(templates.iter().any(|(name, _)| name == &"bug-fix"));
354        assert!(templates
355            .iter()
356            .any(|(name, _)| name == &"performance-optimization"));
357        assert!(templates.iter().any(|(name, _)| name == &"security-audit"));
358        assert!(templates.iter().any(|(name, _)| name == &"api-integration"));
359        assert!(templates
360            .iter()
361            .any(|(name, _)| name == &"database-migration"));
362        assert!(templates
363            .iter()
364            .any(|(name, _)| name == &"dependency-update"));
365        assert!(templates.iter().any(|(name, _)| name == &"cli-tool"));
366        assert!(templates.iter().any(|(name, _)| name == &"web-api"));
367        assert!(templates.iter().any(|(name, _)| name == &"data-pipeline"));
368        assert!(templates.iter().any(|(name, _)| name == &"ui-component"));
369        assert!(templates.iter().any(|(name, _)| name == &"code-review"));
370        assert!(templates.iter().any(|(name, _)| name == &"debug-triage"));
371        assert!(templates.iter().any(|(name, _)| name == &"release"));
372        assert!(templates.iter().any(|(name, _)| name == &"tech-debt"));
373        assert!(templates.iter().any(|(name, _)| name == &"onboarding"));
374    }
375
376    #[test]
377    fn test_template_content_has_goal() {
378        for template in ALL_TEMPLATES {
379            let content = template.content();
380            assert!(
381                content.contains("## Goal"),
382                "Template {} missing Goal section",
383                template.name()
384            );
385        }
386    }
387
388    #[test]
389    fn test_template_content_has_acceptance() {
390        for template in ALL_TEMPLATES {
391            let content = template.content();
392            assert!(
393                content.contains("## Acceptance") || content.contains("## Acceptance Checks"),
394                "Template {} missing Acceptance section",
395                template.name()
396            );
397        }
398    }
399}