Tool System Deep Dive
Note: This section is undergoing deep review. While these notes provide a useful overview, they are not yet as detailed or polished as other sections. Please file a GitHub issue if you notice any errors or have suggestions for additional content.
The power of Claude Code comes from its extensive tool system that allows Claude to interact with your local environment. This section analyzes each key tool in detail, exploring their implementation, integration points, and technical nuances.
Below you'll find detailed descriptions of each tool, with individual pages for each tool implementation:
- Agent: Delegated task execution
- Architect: Software architecture planning
- Bash: Command-line execution
- FileEdit: Precise file modifications
- FileRead: Content examination
- FileWrite: File creation and updates
- Glob: Pattern-based file matching
- Grep: Content search across files
- LS: Directory listing
- MCP: External tool integration
- MemoryRead: State persistence reading
- MemoryWrite: State persistence writing
- NotebookEdit: Notebook modification
- NotebookRead: Jupyter notebook inspection
- StickerRequest: User engagement
- Think: Structured reasoning
Creating Your Own Tools
Before diving into specific tools, here's how you'd build your own tool in TypeScript:
import { z } from "zod";
import { Tool } from "./Tool";
// Define a custom search tool that finds text in files
export const SearchTool: Tool = {
// Name must be unique and descriptive
name: "Search",
// Description tells Claude what this tool does
description: "Searches files for specific text patterns",
// Define expected parameters using Zod schema
inputSchema: z.object({
query: z.string().describe("The text pattern to search for"),
path: z.string().optional().describe("Optional directory to search in"),
fileTypes: z
.array(z.string())
.optional()
.describe("File extensions to include"),
}),
// Is this a read-only operation?
isReadOnly: () => true, // Enables parallel execution
// Does this require user permission?
needsPermissions: (input) => {
// Only need permission for certain paths
return input.path && !input.path.startsWith("/safe/path");
},
// The actual implementation as an async generator
async *call(input, context) {
const { query, path = process.cwd(), fileTypes } = input;
// Check for abort signal (enables cancellation)
if (context.signal?.aborted) {
throw new Error("Operation canceled");
}
try {
// Yield initial status
yield { status: "Searching for files..." };
// Implementation logic here...
const results = await performSearch(query, path, fileTypes);
// Yield results progressively as they come in
for (const result of results) {
yield {
file: result.path,
line: result.lineNumber,
content: result.matchedText,
};
// Check for abort between results
if (context.signal?.aborted) {
throw new Error("Operation canceled");
}
}
// Yield final summary
yield {
status: "complete",
totalMatches: results.length,
searchTime: performance.now() - startTime,
};
} catch (error) {
// Handle and report errors properly
yield { error: error.message };
}
},
};