scud/commands/spawn/
agent.rs

1//! Agent prompt generation for Claude Code sessions
2//!
3//! Creates prompts that provide task context and instructions for Claude Code agents.
4
5use crate::models::task::Task;
6
7/// Generate a prompt for Claude Code with task context
8pub fn generate_prompt(task: &Task, tag: &str) -> String {
9    let mut prompt = format!(
10        r#"You are working on SCUD task {id}: {title}
11
12Tag: {tag}
13Complexity: {complexity}
14Priority: {priority:?}
15
16Description:
17{description}
18"#,
19        id = task.id,
20        title = task.title,
21        tag = tag,
22        complexity = task.complexity,
23        priority = task.priority,
24        description = task.description,
25    );
26
27    // Add details if present
28    if let Some(ref details) = task.details {
29        prompt.push_str(&format!(
30            r#"
31Technical Details:
32{}
33"#,
34            details
35        ));
36    }
37
38    // Add test strategy if present
39    if let Some(ref test_strategy) = task.test_strategy {
40        prompt.push_str(&format!(
41            r#"
42Test Strategy:
43{}
44"#,
45            test_strategy
46        ));
47    }
48
49    // Add dependencies info if any
50    if !task.dependencies.is_empty() {
51        prompt.push_str(&format!(
52            r#"
53Dependencies (should be done):
54{}
55"#,
56            task.dependencies.join(", ")
57        ));
58    }
59
60    // Add instructions
61    prompt.push_str(&format!(
62        r#"
63Instructions:
641. First, explore the codebase to understand the context for this task
652. Implement the task following project conventions and patterns
663. Write tests if applicable based on the test strategy
674. When complete, run: scud set-status {} done
685. If blocked by issues, run: scud set-status {} blocked
69
70Begin by understanding what needs to be done and exploring relevant code.
71"#,
72        task.id, task.id
73    ));
74
75    prompt
76}
77
78/// Generate a shorter prompt for tasks with less context
79pub fn generate_minimal_prompt(task: &Task, tag: &str) -> String {
80    format!(
81        r#"SCUD Task {}: {}
82
83Tag: {}
84Description: {}
85
86When done: scud set-status {} done
87If blocked: scud set-status {} blocked
88"#,
89        task.id,
90        task.title,
91        tag,
92        task.description,
93        task.id,
94        task.id
95    )
96}
97
98#[cfg(test)]
99mod tests {
100    use super::*;
101    use crate::models::task::Task;
102
103    #[test]
104    fn test_generate_prompt_basic() {
105        let task = Task::new(
106            "auth:1".to_string(),
107            "Implement login".to_string(),
108            "Add user authentication flow".to_string(),
109        );
110
111        let prompt = generate_prompt(&task, "auth");
112
113        assert!(prompt.contains("auth:1"));
114        assert!(prompt.contains("Implement login"));
115        assert!(prompt.contains("Tag: auth"));
116        assert!(prompt.contains("scud set-status auth:1 done"));
117    }
118
119    #[test]
120    fn test_generate_prompt_with_details() {
121        let mut task = Task::new(
122            "api:2".to_string(),
123            "Add endpoint".to_string(),
124            "Create REST endpoint".to_string(),
125        );
126        task.details = Some("Use Express.js router pattern".to_string());
127        task.test_strategy = Some("Unit test with Jest".to_string());
128
129        let prompt = generate_prompt(&task, "api");
130
131        assert!(prompt.contains("Technical Details:"));
132        assert!(prompt.contains("Express.js router"));
133        assert!(prompt.contains("Test Strategy:"));
134        assert!(prompt.contains("Unit test with Jest"));
135    }
136
137    #[test]
138    fn test_generate_minimal_prompt() {
139        let task = Task::new(
140            "fix:1".to_string(),
141            "Quick fix".to_string(),
142            "Fix typo".to_string(),
143        );
144
145        let prompt = generate_minimal_prompt(&task, "fix");
146
147        assert!(prompt.contains("fix:1"));
148        assert!(prompt.contains("Quick fix"));
149        assert!(!prompt.contains("Technical Details"));
150    }
151}