use crate::constants::env::ai;
use crate::skills::loader::HooksSettings;
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum BuiltInAgentType {
GeneralPurpose,
Explore,
Plan,
Verification,
CodeGuide,
StatuslineSetup,
}
impl BuiltInAgentType {
pub fn as_str(&self) -> &'static str {
match self {
BuiltInAgentType::GeneralPurpose => "general-purpose",
BuiltInAgentType::Explore => "explore",
BuiltInAgentType::Plan => "plan",
BuiltInAgentType::Verification => "verification",
BuiltInAgentType::CodeGuide => "code-guide",
BuiltInAgentType::StatuslineSetup => "statusline-setup",
}
}
}
#[derive(Debug, Clone)]
pub struct BuiltInAgent {
pub agent_type: BuiltInAgentType,
pub name: String,
pub description: String,
pub get_system_prompt: fn() -> String,
pub skills: Option<Vec<String>>,
pub hooks: Option<HooksSettings>,
pub mcp_servers: Option<Vec<String>>,
pub max_turns: Option<u32>,
pub omit_claude_md: bool,
}
impl BuiltInAgent {
pub fn get_system_prompt(&self) -> String {
(self.get_system_prompt)()
}
}
fn general_purpose_system_prompt() -> String {
r#"You are a general-purpose AI assistant helping with software development tasks.
Your goal is to assist the user with whatever task they present, combining your abilities as a coding, reasoning, and command-line assistant.
When working on code:
- Write clean, maintainable code
- Follow best practices for the language/framework
- Consider edge cases and error handling
- Write tests when appropriate
When you need more information to complete a task, ask the user clarifying questions.
Use the available tools to explore the codebase, read and write files, run commands, and accomplish the user's goals."#.to_string()
}
fn explore_system_prompt() -> String {
r#"You are an exploration agent. Your goal is to thoroughly investigate a codebase or problem area.
Your approach:
1. Start by understanding the overall structure
2. Identify key files and their purposes
3. Trace through important code paths
4. Look for patterns and conventions
5. Document your findings clearly
Be systematic and thorough. Use Glob, Grep, and Read tools to explore comprehensively.
Provide detailed findings with file paths and line numbers to help the user understand the codebase."#.to_string()
}
fn plan_system_prompt() -> String {
r#"You are a planning agent. Your goal is to design implementation plans for complex tasks.
Your approach:
1. Understand the requirements thoroughly
2. Break down into discrete steps
3. Identify dependencies and potential issues
4. Consider alternatives and trade-offs
5. Create a clear, actionable plan
When planning:
- Think step by step
- Consider edge cases
- Identify what needs to be tested
- Make sure the plan is practical and achievable
Present your plan in a clear format with numbered steps."#
.to_string()
}
fn verification_system_prompt() -> String {
r#"You are a verification agent. Your goal is to verify that work is complete and correct.
Your approach:
1. Understand what was supposed to be accomplished
2. Check that all requirements are met
3. Run tests and verify they pass
4. Look for potential issues or bugs
5. Verify code quality and best practices
Be thorough - don't just check that code compiles, verify it actually works correctly.
When you find issues, be specific about what's wrong and suggest fixes."#
.to_string()
}
fn code_guide_system_prompt() -> String {
r#"You are a code guide agent. Your goal is to help users understand and navigate Claude Code.
Your approach:
1. Answer questions about Claude Code features
2. Explain how to use tools effectively
3. Help with debugging and troubleshooting
4. Provide guidance on best practices
5. Explain Claude Code concepts and workflows
Be helpful and informative. Draw on your knowledge of Claude Code to assist users."#
.to_string()
}
fn statusline_setup_system_prompt() -> String {
r#"You are a statusline setup agent. Your goal is to help configure the Claude Code statusline.
Your approach:
1. Check current statusline configuration
2. Understand available components
3. Help customize the statusline to user preferences
4. Ensure configuration is valid
Provide clear guidance on statusline options and help users get their ideal setup."#
.to_string()
}
pub fn get_built_in_agents() -> Vec<BuiltInAgent> {
vec![
BuiltInAgent {
agent_type: BuiltInAgentType::GeneralPurpose,
name: "General Purpose".to_string(),
description: "A general-purpose agent for any task".to_string(),
get_system_prompt: general_purpose_system_prompt,
skills: None,
hooks: None,
mcp_servers: None,
max_turns: Some(50),
omit_claude_md: false,
},
BuiltInAgent {
agent_type: BuiltInAgentType::Explore,
name: "Explore".to_string(),
description: "Explore and understand a codebase".to_string(),
get_system_prompt: explore_system_prompt,
skills: Some(vec!["superpowers:brainstorming".to_string()]),
hooks: None,
mcp_servers: None,
max_turns: Some(20),
omit_claude_md: false,
},
BuiltInAgent {
agent_type: BuiltInAgentType::Plan,
name: "Plan".to_string(),
description: "Create implementation plans".to_string(),
get_system_prompt: plan_system_prompt,
skills: Some(vec!["superpowers:writing-plans".to_string()]),
hooks: None,
mcp_servers: None,
max_turns: Some(15),
omit_claude_md: false,
},
BuiltInAgent {
agent_type: BuiltInAgentType::Verification,
name: "Verification".to_string(),
description: "Verify work is complete and correct".to_string(),
get_system_prompt: verification_system_prompt,
skills: Some(vec![
"superpowers:verification-before-completion".to_string(),
"simplify".to_string(),
]),
hooks: None,
mcp_servers: None,
max_turns: Some(25),
omit_claude_md: false,
},
BuiltInAgent {
agent_type: BuiltInAgentType::CodeGuide,
name: "Code Guide".to_string(),
description: "Help with Claude Code features".to_string(),
get_system_prompt: code_guide_system_prompt,
skills: None,
hooks: None,
mcp_servers: None,
max_turns: Some(10),
omit_claude_md: true,
},
BuiltInAgent {
agent_type: BuiltInAgentType::StatuslineSetup,
name: "Statusline Setup".to_string(),
description: "Configure Claude Code statusline".to_string(),
get_system_prompt: statusline_setup_system_prompt,
skills: None,
hooks: None,
mcp_servers: None,
max_turns: Some(5),
omit_claude_md: true,
},
]
}
pub fn get_built_in_agent(agent_type: BuiltInAgentType) -> Option<BuiltInAgent> {
get_built_in_agents()
.into_iter()
.find(|a| a.agent_type == agent_type)
}
pub fn get_agent_by_type_name(type_name: &str) -> Option<BuiltInAgent> {
let agent_type = match type_name {
"general-purpose" | "general" => Some(BuiltInAgentType::GeneralPurpose),
"explore" => Some(BuiltInAgentType::Explore),
"plan" => Some(BuiltInAgentType::Plan),
"verification" | "verify" => Some(BuiltInAgentType::Verification),
"code-guide" | "guide" => Some(BuiltInAgentType::CodeGuide),
"statusline-setup" | "statusline" => Some(BuiltInAgentType::StatuslineSetup),
_ => None,
};
agent_type.and_then(get_built_in_agent)
}
pub fn are_explore_plan_agents_enabled() -> bool {
std::env::var(ai::DISABLE_EXPLORE_PLAN_AGENTS)
.map(|v| v != "true")
.unwrap_or(true)
}
pub fn get_enabled_built_in_agents() -> Vec<BuiltInAgent> {
let mut agents = get_built_in_agents();
if !are_explore_plan_agents_enabled() {
agents.retain(|a| {
a.agent_type != BuiltInAgentType::Explore && a.agent_type != BuiltInAgentType::Plan
});
}
agents
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_built_in_agents() {
let agents = get_built_in_agents();
assert!(!agents.is_empty());
}
#[test]
fn test_get_agent_by_type_name() {
let agent = get_agent_by_type_name("explore");
assert!(agent.is_some());
assert_eq!(agent.unwrap().agent_type, BuiltInAgentType::Explore);
}
#[test]
fn test_get_nonexistent_agent() {
let agent = get_agent_by_type_name("nonexistent");
assert!(agent.is_none());
}
#[test]
fn test_agent_system_prompt() {
let agent = get_built_in_agent(BuiltInAgentType::Explore).unwrap();
let prompt = agent.get_system_prompt();
assert!(!prompt.is_empty());
}
#[test]
fn test_are_explore_plan_agents_enabled_default() {
assert!(are_explore_plan_agents_enabled());
}
}