
How Claude Code Optimizes Tool Calling
After reading the claude-code source code, I found that its tool calling optimization relies not on a single trick, but on multiple layers of mechanisms working together.
After reading the claude-code source code, I found that its tool calling optimization relies not on a single trick, but on multiple layers of mechanisms working together.
The most valuable insights can be grouped into six categories.
1. Tools Teach the Model How to Use Them
The most direct optimization is written in each tool's prompt.
GrepTool/prompt.ts explicitly states: "ALWAYS use GrepTool for search tasks", "NEVER invoke grep or rg as Bash command". The GlobTool prompt tells the model that this tool finds files by name pattern and when to use it. WebFetchTool even says to prefer dedicated tools when available.
These prompts don't just describe functionality—they explicitly tell the model: what problem this tool solves, when to use it, when not to use it, and why it's better than alternatives. This guidance significantly improves accuracy.
When building an agent system, tool definitions are often "schema-correct" but lack sufficient "selection guidance". The next step is to add: when glob_files is better than grep_code, when read_file_range is better than read_text_file, etc.
2. Lowering Bash's Appeal
BashTool/prompt.ts contains many "don't use Bash for these tasks" rules: don't use shell for search, don't use shell for reading files, don't use shell for finding files—prefer dedicated tools.
This is more important than simply adding new tools. Without these constraints, the model often thinks shell is more universal, more familiar, and "good enough", then falls back to Bash.
If you already have "prefer dedicated tools" in the system prompt, it could be stronger—for example: "Do not use shell commands for file discovery, JSON reading, line-range reads, or git status when a dedicated tool exists."
The design philosophy here: universal tools are necessary backup, but their priority must be lower than dedicated tools. Dedicated tools are refined best practices, while universal tools require the agent to orchestrate them itself, which is prone to errors.
3. Tool Search Mechanism
The code shows searchHint, toAutoClassifierInput, ToolSearchTool, and logic for sorting/matching by searchHint.
Instead of flattening all tools to the model, each tool declares a high-signal capability phrase, like "find files by name pattern" or "search file contents with regex". When there are many tools, ToolSearchTool filters first, then loads the schema.
This significantly reduces the "too many tools, model doesn't know which to choose" problem.
When the tool count is still small, you don't need full ToolSearch yet. But you can start by adding a short, strong capability hint to each tool—for example, glob_files maps to "find files by wildcard pattern", list_files maps to "inspect directory contents". When the tool count grows, then consider a lightweight tool search mechanism.
4. Model-Friendly Schema and Output
GlobTool, GrepTool, and FileReadTool share these traits: clear input schema, structured output fields, while preserving human-readable text. They also explicitly tell the model whether results are truncated, how many results there are, and which segment is being returned.
These fields (numFiles, truncated, startLine, totalLines, etc.) help the model form stable usage habits. The model understands this tool isn't a black box—results can be paginated, narrowed, and queried further.
If you're designing a similar toolset, move in this direction: strengthen read_json result boundary control, glob_files/list_files limit and truncated feedback, and make read_file_range explicitly highlight start/end line numbers.
This creates interaction between tools and the agent, rather than the agent passively receiving tool results. The more semantic the tool output, the better the agent can decide next steps based on that semantics.
5. System Context Pre-Influence
context.ts, systemInit.ts, systemPrompt.ts and various tool prompts carry git status, current date, CLAUDE.md, etc. Some scenarios explicitly declare tool constraints in system prompts—for example, Chrome/MCP might say: before using these tools, you must do X first.
This shows they highly value giving the model correct behavioral hints before it prepares to call tools.
The function that builds your system prompt is a critical location. If you want to continue optimizing accuracy, this is where to focus. Especially: make tool usage strategies more behavioral, not just listing names. For example:
- Use
list_filesto understand directory structure - Use
glob_filesto find files by pattern - Use
read_file_rangeto read partial large files - Use
read_jsonto understand JSON config - Use
git_statusto understand working directory state - Only fall back to generic shell commands when dedicated tools can't do it
System prompt is fixed context passed to the model every round—how this is assembled is key. Currently it's dynamically assembled: different prompts are passed for different scenarios and tool calls.
6. Shrinking the Visible Tool Set
The code has getAllBaseTools(), getTools(), deny rules, feature flags, simple mode, ToolSearch. They filter the actual tools exposed to the model based on feature flag, current mode, deny rules, and environment capabilities.
Fewer tools means less ambiguity; more focused tools means more stable choices.
In the early stages, you don't need complex feature flags yet, but can do one very effective thing: keep the default registered tool set minimal, don't add too many overlapping tools too early. For example, if you already have git_status, don't let the model bias toward shell commands + git status for this task.
Summary: claude-code's tool calling optimization isn't a single technique, but the combined effect of prompt engineering, schema design, tool search, context management, and tool set management. For developers building agent systems, the highest priority is the first two layers: give tools stronger self-description capabilities, and more explicitly constrain tool selection in the system prompt.


