Tool Use System¶
Overview¶
The Tool Use System is the mechanism by which Claude Code exposes capabilities and receives instructions from Claude. Tools are the primary interface through which Claude takes actions in the system - executing commands, reading files, calling APIs, spawning agents, and more.
Architecture¶
┌────────────────────────────────────────┐
│ Claude API Response │
│ Contains tool_use blocks │
└────────────────┬───────────────────────┘
↓
┌─────────────────────┐
│ Parse Tool Calls │
│ Extract parameters │
└────────────┬────────┘
↓
┌─────────────────────────────────┐
│ Permission Check │
│ • User auto-approval rules │
│ • Classifier evaluation │
│ • Interactive prompts │
└────────────┬────────────────────┘
↓
┌─────────────────────────────────┐
│ Input Validation (Zod) │
│ Verify parameters match schema │
└────────────┬────────────────────┘
↓
┌─────────────────────────────────┐
│ Tool Execution │
│ • Call tool.call() method │
│ • Handle errors │
│ • Capture output │
└────────────┬────────────────────┘
↓
┌─────────────────────────────────┐
│ Result Rendering │
│ • Format output │
│ • Create tool_result block │
│ • Add to message stream │
└─────────────────────────────────┘
Tool Interface¶
Every tool implements the Tool interface defined in src/Tool.ts:
interface Tool {
// Metadata
name: string // Unique identifier (e.g., "Bash")
userFacingName(): string // Display name for users
description(): string // Brief description for Claude
// Schemas
inputSchema: ZodSchema // Parameter validation
outputSchema?: ZodSchema // Optional output validation
// Core Methods
call(input: InputType): Promise<ToolResult>
checkPermissions(input: InputType, context: PermissionContext)
: Promise<PermissionResult>
// Validation
validateInput(input: unknown): Promise<void>
// UI Rendering
renderToolUseMessage(input: InputType): React.ReactNode
renderToolResultMessage(result: ToolResult): React.ReactNode
renderToolUseProgressMessage(update: ProgressUpdate): React.ReactNode
// Metadata
isConcurrencySafe(): boolean // Safe to run in parallel?
isReadOnly(): boolean // No side effects?
isDestructive(): boolean // Irreversible operation?
}
Built-in Tools¶
Claude Code provides 60+ built-in tools organized by category:
File & Code Operations¶
| Tool | Purpose | Location |
|---|---|---|
| Bash | Execute shell commands | /src/tools/BashTool/ |
| Read | Read file contents | /src/tools/FileReadTool/ |
| Edit | Replace text in files | /src/tools/FileEditTool/ |
| Write | Write new files | /src/tools/FileWriteTool/ |
| Glob | Find files by pattern | /src/tools/GlobTool/ |
| Grep | Search file contents | /src/tools/GrepTool/ |
| Notebook Edit | Edit Jupyter notebook cells | /src/tools/NotebookEditTool/ |
Web & API¶
| Tool | Purpose |
|---|---|
| WebFetch | Fetch and parse URLs |
| WebSearch | Search the web |
Agent & Task Management¶
| Tool | Purpose |
|---|---|
| Agent (Task tool) | Spawn subagents |
| Skill | Execute skills (reusable prompts) |
| TaskList | List tasks |
| TaskCreate | Create new tasks |
| TaskGet | Get single task |
| TaskUpdate | Update task status/metadata |
Team & Collaboration¶
| Tool | Purpose |
|---|---|
| TeamCreate | Create agent teams |
| TeamDelete | Delete teams |
Planning & Execution¶
| Tool | Purpose |
|---|---|
| EnterPlanMode | Enter structured planning mode |
| ExitPlanMode | Complete plan and request approval |
System & State¶
| Tool | Purpose |
|---|---|
| KillShell | Terminate background processes |
| TaskOutput | Get output from background tasks |
| Env | Read environment variables |
Tool Definitions & Schemas¶
Tools are exposed to Claude via OpenAI-compatible tool definitions. The system dynamically generates these based on tool configurations:
Tool Definition Structure¶
{
"name": "Bash",
"description": "Execute bash commands with optional timeout",
"input_schema": {
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "The bash command to execute"
},
"timeout": {
"type": "number",
"description": "Timeout in milliseconds"
}
},
"required": ["command"]
}
}
Zod Schema Validation¶
Tools use Zod for runtime validation:
// BashTool example
const inputSchema = z.object({
command: z.string().describe("The bash command to execute"),
timeout: z.number().optional().describe("Timeout in milliseconds"),
description: z.string().describe("What this command does"),
run_in_background: z.boolean().optional()
})
// Called by: validateInput(input)
// Throws ZodError if invalid
Execution Flow¶
1. Tool Call Parsing¶
Claude's response contains:
<tool_use id="abc123" name="Bash" input='{"command":"ls -la"}'>
The system extracts:
- Tool name: "Bash"
- Parameters: {command: "ls -la"}
- Tool use ID: "abc123" (for result association)
2. Permission Checking¶
For each tool call, checkPermissions() is invoked:
const permission = await tool.checkPermissions(input, {
userId: "claude",
sessionId: "...",
toolName: "Bash",
operation: "execute",
context: "query_loop"
})
// Returns: { behavior: "allow" | "deny" | "ask" }
Permission Rules: - Auto-allow - Pre-approved operations (read-only files) - Auto-deny - Blocked operations (destructive without confirmation) - Ask - Interactive prompts for sensitive operations - Classify - ML classifier evaluates safety
3. Input Validation¶
try {
await tool.validateInput(input)
} catch (error) {
// Return validation error to Claude
// Claude can retry with corrected input
}
4. Tool Invocation¶
const result = await tool.call(input)
// Returns: { stdout?: string, stderr?: string, exitCode?: number }
// or specific format for tool
5. Result Formatting¶
The tool's renderToolResultMessage() formats output:
// Bash tool renders:
{
type: "tool_result",
tool_use_id: "abc123",
content: [{
type: "text",
text: "command output..."
}]
}
Concurrent Tool Execution¶
When Claude's response contains multiple tool calls, they execute in parallel:
const toolCalls = [
{ name: "Read", input: { file_path: "/file1" } },
{ name: "Grep", input: { pattern: "foo", path: "/file2" } },
{ name: "Bash", input: { command: "ls" } }
]
// All three execute simultaneously
const results = await Promise.all(
toolCalls.map(call => executeTool(call))
)
Benefits: - Faster wall-clock execution - Better utilization of system resources - Reduced latency vs. sequential execution
Constraints:
- Tools must declare isConcurrencySafe() = true
- Default is false (assume unsafe)
- Bash, Read, Glob, WebFetch are safe
- Edit, Write, FileOperations are unsafe
Tool Result Integration¶
Tool results are added back to the message stream as tool_result blocks:
const updatedMessages = [
...previousMessages,
{
role: "assistant",
content: [
{ type: "text", text: "I'll check the file..." },
{ type: "tool_use", name: "Read", input: {...}, id: "abc" }
]
},
{
role: "user",
content: [
{
type: "tool_result",
tool_use_id: "abc",
content: [{
type: "text",
text: "File contents..."
}]
}
]
}
]
The loop continues with Claude seeing these results and deciding next steps.
Special Tool Types¶
Agent Tool (Spawn Subagents)¶
Spawns isolated subagents to handle specialized tasks:
// Input
{
description: "Analyze code for bugs",
subagent_type: "explorer", // or "general-purpose"
prompt: "Find the bug in src/main.ts"
}
// Returns
{
status: "completed",
output: "Found bug at line 42..."
}
Key features: - Isolated context via AsyncLocalStorage - Own message history - Shared prompt cache (cheaper) - Can spawn further subagents (unlimited nesting)
Skill Tool (Execute Skills)¶
Executes reusable skill prompts:
// Input
{
skill: "write-unit-test",
args: {
file: "src/api.ts",
testFramework: "jest"
}
}
// Internally:
// 1. Load skill .md file
// 2. Parse frontmatter for configuration
// 3. Create subagent with skill prompt
// 4. Inject args via user message
// 5. Execute and return results
Task Tools (Create/List/Update Tasks)¶
Manage persistent task lists:
// TaskCreate
{
subject: "Fix authentication bug",
description: "JWT tokens expire too quickly...",
activeForm: "Fixing auth bug"
}
// TaskList
// Returns all tasks with status, owner, dependencies
// TaskUpdate
{
taskId: "task-123",
status: "in_progress",
owner: "agent-xyz"
}
Permission System¶
Permission Rules¶
Rules are defined in configuration and control tool access:
interface PermissionRule {
toolName: string // "Bash", "Edit", etc.
pathPattern?: string // Glob pattern
behavior: "allow" | "deny" | "ask" | "classify"
reason?: string // Explanation for users
}
// Examples:
{ toolName: "Read", behavior: "allow" } // All reads OK
{ toolName: "Edit", pathPattern: "src/**", behavior: "ask" } // Prompt for code edits
{ toolName: "Bash", behavior: "classify" } // ML classifier decides
Permission Modes¶
Global permission mode affects all tool execution:
| Mode | Behavior |
|---|---|
default |
Prompt user for each decision |
bypass |
Auto-allow all (dangerous!) |
deferToClassifier |
Use ML classifier for decisions |
delegatedByTeamLead |
Accept decisions from team lead |
Interactive Permission Prompts¶
When behavior: "ask", user is prompted:
BashTool wants to execute: "rm -rf /important"
⚠️ This is a destructive operation that cannot be undone.
[Allow Once] [Allow Always] [Deny] [Cancel]
Tool Development & Registration¶
Creating Custom Tools¶
New tools must implement the Tool interface:
import { buildTool } from "src/Tool"
import { z } from "zod"
export const MyTool = buildTool({
name: "MyTool",
description: "Does something useful",
inputSchema: z.object({
param1: z.string().describe("Required parameter"),
param2: z.number().optional()
}),
async call(input) {
// Execute tool logic
return { success: true, output: "result" }
},
checkPermissions(input, context) {
// Allow if safe, deny if risky
return { behavior: "allow" }
},
isConcurrencySafe() {
return true // Safe to run in parallel
},
renderToolUseMessage(input) {
return <p>Executing with {input.param1}</p>
},
renderToolResultMessage(result) {
return <pre>{JSON.stringify(result)}</pre>
}
})
Tool Registration¶
Tools are registered in src/commands.ts and exposed to Claude:
const tools: Tool[] = [
BashTool,
FileReadTool,
FileEditTool,
MyTool, // New custom tool
// ... more tools
]
Error Handling¶
Tools can signal errors which Claude receives:
// In tool result
{
type: "tool_result",
tool_use_id: "abc123",
is_error: true,
content: [{
type: "text",
text: "Permission denied: /etc/passwd is protected"
}]
}
Claude then: - Acknowledges the error - Adjusts strategy - Retries with different parameters - Or terminates if unrecoverable
Performance Optimizations¶
1. Concurrent Execution¶
As discussed above - multiple tools run in parallel when safe.
2. Input Pre-validation¶
Zod schemas catch invalid parameters before tool execution:
// Fast failure before expensive operations
validateInput(input) throws immediately for bad input
3. Output Streaming¶
Some tools (Bash) stream output as available: - Don't wait for full completion - User sees progress immediately - Better interactivity
4. Caching¶
- File contents cached (invalidated on edits)
- Glob results cached (invalidated on writes)
- Reduces repeated tool calls
Key Files¶
| File | Purpose |
|---|---|
src/Tool.ts |
Tool interface and base implementation |
src/tools/BashTool/ |
Shell command execution |
src/tools/FileReadTool/ |
File reading |
src/tools/FileEditTool/ |
Text replacement in files |
src/tools/GrepTool/ |
Content searching |
src/tools/AgentTool/ |
Subagent spawning |
src/tools/SkillTool/ |
Skill execution |
src/tools/TaskListTool/ |
Task management |
src/hooks/toolPermission/ |
Permission checking |
See Also¶
- Agent Loop - How tools are called in the main loop
- Subagents - Agent Tool details
- Skills - Skill Tool mechanics
- Tasks - Task tool ecosystem
- Permissions - Permission system details