claude_agent/subagents/
builtin.rs1use super::SubagentIndex;
4use crate::client::ModelType;
5use crate::common::{ContentSource, SourceType};
6
7pub fn bash_subagent() -> SubagentIndex {
10 SubagentIndex::new(
11 "Bash",
12 "Command execution specialist for running bash commands. Use this for git operations, command execution, and other terminal tasks.",
13 )
14 .with_source(ContentSource::in_memory(
15 r#"You are a Bash agent specialized for command execution.
16
17Your task is to execute shell commands efficiently and safely:
18- Run git operations (status, diff, log, commit, push, etc.)
19- Execute build and test commands
20- Perform system operations
21
22Always verify command safety before execution. Return clear, concise results."#,
23 ))
24 .with_source_type(SourceType::Builtin)
25 .with_tools(["Bash"])
26 .with_model_type(ModelType::Small)
27}
28
29pub fn explore_subagent() -> SubagentIndex {
32 SubagentIndex::new(
33 "Explore",
34 "Fast agent specialized for exploring codebases. Use this when you need to quickly find files by patterns, search code for keywords, or answer questions about the codebase. When calling this agent, specify the desired thoroughness level: \"quick\" for basic searches, \"medium\" for moderate exploration, or \"very thorough\" for comprehensive analysis across multiple locations and naming conventions.",
35 )
36 .with_source(ContentSource::in_memory(
37 r#"You are an Explore agent specialized for investigating codebases.
38
39Your task is to quickly find relevant information through:
40- Pattern matching with Glob (e.g., "src/components/**/*.tsx")
41- Content search with Grep (e.g., "API endpoints", "function\\s+\\w+")
42- File reading with Read
43
44Thoroughness levels:
45- "quick": Basic searches, first matches only
46- "medium": Moderate exploration, check multiple locations
47- "very thorough": Comprehensive analysis across multiple locations and naming conventions
48
49Be thorough but efficient. Return a concise summary of your findings."#,
50 ))
51 .with_source_type(SourceType::Builtin)
52 .with_tools(["Read", "Grep", "Glob", "Bash", "TodoWrite", "KillShell"])
53 .with_model_type(ModelType::Small)
54}
55
56pub fn plan_subagent() -> SubagentIndex {
59 SubagentIndex::new(
60 "Plan",
61 "Software architect agent for designing implementation plans. Use this when you need to plan the implementation strategy for a task. Returns step-by-step plans, identifies critical files, and considers architectural trade-offs.",
62 )
63 .with_source(ContentSource::in_memory(
64 r#"You are a Plan agent for designing implementation strategies.
65
66Your task is to:
671. Understand the requirements thoroughly
682. Explore the codebase to understand existing patterns and context
693. Identify critical files that will need modification
704. Design a step-by-step implementation plan
715. Consider architectural trade-offs and potential issues
72
73Present your plan clearly with:
74- Numbered implementation steps
75- Files to be modified/created
76- Potential risks or considerations
77- Recommended approach with rationale"#,
78 ))
79 .with_source_type(SourceType::Builtin)
80 .with_tools(["Read", "Grep", "Glob", "Bash", "TodoWrite", "KillShell"])
81 .with_model_type(ModelType::Primary)
82}
83
84pub fn general_purpose_subagent() -> SubagentIndex {
87 SubagentIndex::new(
88 "general-purpose",
89 "General-purpose agent for researching complex questions, searching for code, and executing multi-step tasks. When you are searching for a keyword or file and are not confident that you will find the right match in the first few tries, use this agent to perform the search for you.",
90 )
91 .with_source(ContentSource::in_memory(
92 r#"You are a general-purpose agent capable of handling complex, multi-step tasks.
93
94You have full access to all tools and can:
95- Read and modify files
96- Execute shell commands
97- Search and explore codebases
98- Implement features and fix bugs
99- Create and manage tasks
100
101Work autonomously and methodically:
1021. Understand the task requirements
1032. Plan your approach
1043. Execute step by step
1054. Verify results
1065. Return comprehensive results when complete"#,
107 ))
108 .with_source_type(SourceType::Builtin)
109 .with_model_type(ModelType::Primary)
110}
111
112pub fn builtin_subagents() -> Vec<SubagentIndex> {
113 vec![
114 bash_subagent(),
115 explore_subagent(),
116 plan_subagent(),
117 general_purpose_subagent(),
118 ]
119}
120
121pub fn find_builtin(name: &str) -> Option<SubagentIndex> {
122 match name {
123 "Bash" => Some(bash_subagent()),
124 "Explore" => Some(explore_subagent()),
125 "Plan" => Some(plan_subagent()),
126 "general-purpose" => Some(general_purpose_subagent()),
127 _ => None,
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134 use crate::common::ToolRestricted;
135
136 #[test]
137 fn test_builtin_subagents() {
138 let builtins = builtin_subagents();
139 assert_eq!(builtins.len(), 4);
140
141 let names: Vec<&str> = builtins.iter().map(|s| s.name.as_str()).collect();
142 assert!(names.contains(&"Bash"));
143 assert!(names.contains(&"Explore"));
144 assert!(names.contains(&"Plan"));
145 assert!(names.contains(&"general-purpose"));
146 }
147
148 #[test]
149 fn test_find_builtin_cli_names() {
150 assert!(find_builtin("Bash").is_some());
151 assert!(find_builtin("Explore").is_some());
152 assert!(find_builtin("Plan").is_some());
153 assert!(find_builtin("general-purpose").is_some());
154 assert!(find_builtin("nonexistent").is_none());
155 }
156
157 #[test]
158 fn test_bash_agent_tool_restriction() {
159 let bash = bash_subagent();
160 assert!(bash.has_tool_restrictions());
161 assert!(bash.is_tool_allowed("Bash"));
162 assert!(!bash.is_tool_allowed("Read"));
163 assert!(!bash.is_tool_allowed("Write"));
164 }
165
166 #[test]
167 fn test_explore_has_tool_restrictions() {
168 let explore = explore_subagent();
169 assert!(explore.has_tool_restrictions());
170 assert!(explore.is_tool_allowed("Read"));
171 assert!(explore.is_tool_allowed("Grep"));
172 assert!(explore.is_tool_allowed("Glob"));
173 assert!(explore.is_tool_allowed("Bash"));
174 assert!(!explore.is_tool_allowed("Write"));
176 assert!(!explore.is_tool_allowed("Edit"));
177 }
178
179 #[test]
180 fn test_plan_has_tool_restrictions() {
181 let plan = plan_subagent();
182 assert!(plan.has_tool_restrictions());
183 assert!(plan.is_tool_allowed("Read"));
184 assert!(plan.is_tool_allowed("Grep"));
185 assert!(!plan.is_tool_allowed("Write"));
187 assert!(!plan.is_tool_allowed("Edit"));
188 }
189
190 #[test]
191 fn test_general_purpose_no_restrictions() {
192 let gp = general_purpose_subagent();
193 assert!(!gp.has_tool_restrictions());
194 assert!(gp.is_tool_allowed("Anything"));
195 }
196}