1use crate::constants::env::ai;
6use crate::skills::loader::HooksSettings;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
10#[serde(rename_all = "kebab-case")]
11pub enum BuiltInAgentType {
12 GeneralPurpose,
13 Explore,
14 Plan,
15 Verification,
16 CodeGuide,
17 StatuslineSetup,
18}
19
20impl BuiltInAgentType {
21 pub fn as_str(&self) -> &'static str {
22 match self {
23 BuiltInAgentType::GeneralPurpose => "general-purpose",
24 BuiltInAgentType::Explore => "explore",
25 BuiltInAgentType::Plan => "plan",
26 BuiltInAgentType::Verification => "verification",
27 BuiltInAgentType::CodeGuide => "code-guide",
28 BuiltInAgentType::StatuslineSetup => "statusline-setup",
29 }
30 }
31}
32
33#[derive(Debug, Clone)]
35pub struct BuiltInAgent {
36 pub agent_type: BuiltInAgentType,
38 pub name: String,
40 pub description: String,
42 pub get_system_prompt: fn() -> String,
44 pub skills: Option<Vec<String>>,
46 pub hooks: Option<HooksSettings>,
48 pub mcp_servers: Option<Vec<String>>,
50 pub max_turns: Option<u32>,
52 pub omit_claude_md: bool,
54}
55
56impl BuiltInAgent {
57 pub fn get_system_prompt(&self) -> String {
59 (self.get_system_prompt)()
60 }
61}
62
63fn general_purpose_system_prompt() -> String {
65 r#"You are a general-purpose AI assistant helping with software development tasks.
66
67Your goal is to assist the user with whatever task they present, combining your abilities as a coding, reasoning, and command-line assistant.
68
69When working on code:
70- Write clean, maintainable code
71- Follow best practices for the language/framework
72- Consider edge cases and error handling
73- Write tests when appropriate
74
75When you need more information to complete a task, ask the user clarifying questions.
76
77Use the available tools to explore the codebase, read and write files, run commands, and accomplish the user's goals."#.to_string()
78}
79
80fn explore_system_prompt() -> String {
82 r#"You are an exploration agent. Your goal is to thoroughly investigate a codebase or problem area.
83
84Your approach:
851. Start by understanding the overall structure
862. Identify key files and their purposes
873. Trace through important code paths
884. Look for patterns and conventions
895. Document your findings clearly
90
91Be systematic and thorough. Use Glob, Grep, and Read tools to explore comprehensively.
92
93Provide detailed findings with file paths and line numbers to help the user understand the codebase."#.to_string()
94}
95
96fn plan_system_prompt() -> String {
98 r#"You are a planning agent. Your goal is to design implementation plans for complex tasks.
99
100Your approach:
1011. Understand the requirements thoroughly
1022. Break down into discrete steps
1033. Identify dependencies and potential issues
1044. Consider alternatives and trade-offs
1055. Create a clear, actionable plan
106
107When planning:
108- Think step by step
109- Consider edge cases
110- Identify what needs to be tested
111- Make sure the plan is practical and achievable
112
113Present your plan in a clear format with numbered steps."#
114 .to_string()
115}
116
117fn verification_system_prompt() -> String {
119 r#"You are a verification agent. Your goal is to verify that work is complete and correct.
120
121Your approach:
1221. Understand what was supposed to be accomplished
1232. Check that all requirements are met
1243. Run tests and verify they pass
1254. Look for potential issues or bugs
1265. Verify code quality and best practices
127
128Be thorough - don't just check that code compiles, verify it actually works correctly.
129
130When you find issues, be specific about what's wrong and suggest fixes."#
131 .to_string()
132}
133
134fn code_guide_system_prompt() -> String {
136 r#"You are a code guide agent. Your goal is to help users understand and navigate Claude Code.
137
138Your approach:
1391. Answer questions about Claude Code features
1402. Explain how to use tools effectively
1413. Help with debugging and troubleshooting
1424. Provide guidance on best practices
1435. Explain Claude Code concepts and workflows
144
145Be helpful and informative. Draw on your knowledge of Claude Code to assist users."#
146 .to_string()
147}
148
149fn statusline_setup_system_prompt() -> String {
151 r#"You are a statusline setup agent. Your goal is to help configure the Claude Code statusline.
152
153Your approach:
1541. Check current statusline configuration
1552. Understand available components
1563. Help customize the statusline to user preferences
1574. Ensure configuration is valid
158
159Provide clear guidance on statusline options and help users get their ideal setup."#
160 .to_string()
161}
162
163pub fn get_built_in_agents() -> Vec<BuiltInAgent> {
165 vec![
166 BuiltInAgent {
167 agent_type: BuiltInAgentType::GeneralPurpose,
168 name: "General Purpose".to_string(),
169 description: "A general-purpose agent for any task".to_string(),
170 get_system_prompt: general_purpose_system_prompt,
171 skills: None,
172 hooks: None,
173 mcp_servers: None,
174 max_turns: Some(50),
175 omit_claude_md: false,
176 },
177 BuiltInAgent {
178 agent_type: BuiltInAgentType::Explore,
179 name: "Explore".to_string(),
180 description: "Explore and understand a codebase".to_string(),
181 get_system_prompt: explore_system_prompt,
182 skills: Some(vec!["superpowers:brainstorming".to_string()]),
183 hooks: None,
184 mcp_servers: None,
185 max_turns: Some(20),
186 omit_claude_md: false,
187 },
188 BuiltInAgent {
189 agent_type: BuiltInAgentType::Plan,
190 name: "Plan".to_string(),
191 description: "Create implementation plans".to_string(),
192 get_system_prompt: plan_system_prompt,
193 skills: Some(vec!["superpowers:writing-plans".to_string()]),
194 hooks: None,
195 mcp_servers: None,
196 max_turns: Some(15),
197 omit_claude_md: false,
198 },
199 BuiltInAgent {
200 agent_type: BuiltInAgentType::Verification,
201 name: "Verification".to_string(),
202 description: "Verify work is complete and correct".to_string(),
203 get_system_prompt: verification_system_prompt,
204 skills: Some(vec![
205 "superpowers:verification-before-completion".to_string(),
206 "simplify".to_string(),
207 ]),
208 hooks: None,
209 mcp_servers: None,
210 max_turns: Some(25),
211 omit_claude_md: false,
212 },
213 BuiltInAgent {
214 agent_type: BuiltInAgentType::CodeGuide,
215 name: "Code Guide".to_string(),
216 description: "Help with Claude Code features".to_string(),
217 get_system_prompt: code_guide_system_prompt,
218 skills: None,
219 hooks: None,
220 mcp_servers: None,
221 max_turns: Some(10),
222 omit_claude_md: true,
223 },
224 BuiltInAgent {
225 agent_type: BuiltInAgentType::StatuslineSetup,
226 name: "Statusline Setup".to_string(),
227 description: "Configure Claude Code statusline".to_string(),
228 get_system_prompt: statusline_setup_system_prompt,
229 skills: None,
230 hooks: None,
231 mcp_servers: None,
232 max_turns: Some(5),
233 omit_claude_md: true,
234 },
235 ]
236}
237
238pub fn get_built_in_agent(agent_type: BuiltInAgentType) -> Option<BuiltInAgent> {
240 get_built_in_agents()
241 .into_iter()
242 .find(|a| a.agent_type == agent_type)
243}
244
245pub fn get_agent_by_type_name(type_name: &str) -> Option<BuiltInAgent> {
247 let agent_type = match type_name {
248 "general-purpose" | "general" => Some(BuiltInAgentType::GeneralPurpose),
249 "explore" => Some(BuiltInAgentType::Explore),
250 "plan" => Some(BuiltInAgentType::Plan),
251 "verification" | "verify" => Some(BuiltInAgentType::Verification),
252 "code-guide" | "guide" => Some(BuiltInAgentType::CodeGuide),
253 "statusline-setup" | "statusline" => Some(BuiltInAgentType::StatuslineSetup),
254 _ => None,
255 };
256 agent_type.and_then(get_built_in_agent)
257}
258
259pub fn are_explore_plan_agents_enabled() -> bool {
261 std::env::var(ai::DISABLE_EXPLORE_PLAN_AGENTS)
264 .map(|v| v != "true")
265 .unwrap_or(true)
266}
267
268pub fn get_enabled_built_in_agents() -> Vec<BuiltInAgent> {
270 let mut agents = get_built_in_agents();
271
272 if !are_explore_plan_agents_enabled() {
274 agents.retain(|a| {
275 a.agent_type != BuiltInAgentType::Explore && a.agent_type != BuiltInAgentType::Plan
276 });
277 }
278
279 agents
280}
281
282#[cfg(test)]
283mod tests {
284 use super::*;
285
286 #[test]
287 fn test_get_built_in_agents() {
288 let agents = get_built_in_agents();
289 assert!(!agents.is_empty());
290 }
291
292 #[test]
293 fn test_get_agent_by_type_name() {
294 let agent = get_agent_by_type_name("explore");
295 assert!(agent.is_some());
296 assert_eq!(agent.unwrap().agent_type, BuiltInAgentType::Explore);
297 }
298
299 #[test]
300 fn test_get_nonexistent_agent() {
301 let agent = get_agent_by_type_name("nonexistent");
302 assert!(agent.is_none());
303 }
304
305 #[test]
306 fn test_agent_system_prompt() {
307 let agent = get_built_in_agent(BuiltInAgentType::Explore).unwrap();
308 let prompt = agent.get_system_prompt();
309 assert!(!prompt.is_empty());
310 }
311
312 #[test]
313 fn test_are_explore_plan_agents_enabled_default() {
314 assert!(are_explore_plan_agents_enabled());
316 }
317}