Tool System

Description

The tool system is the interface between the LLM's intentions and the real world. 40+ tools covering file operations, search, execution, web access, task management, and inter-agent communication are defined as self-contained modules in src/tools/<ToolName>/ and registered through a central factory. The architecture prioritizes prompt cache preservation, parallel execution, and lazy loading via deferred tool schemas.

How it works

The buildTool() factory

Every tool is created through buildTool() in src/Tool.ts. It takes a ToolDef and spreads TOOL_DEFAULTS underneath, producing a complete Tool object. Defaults are fail-closed:

A Tool object carries: name, optional aliases (for backwards compatibility), inputSchema (Zod validation), prompt() (generates the system prompt text), call() (execution), checkPermissions(), and rendering methods for UI display.

Key behavioral flags per tool: - isConcurrencySafe(input) — can this tool run in parallel with others? - isReadOnly(input) — does this tool only read? - isDestructive(input) — could this tool cause irreversible harm? - interruptBehavior() — returns 'cancel' or 'block' when the user interrupts - shouldDefer / alwaysLoad — controls lazy loading via ToolSearch

Tool registration (src/tools.ts)

getAllBaseTools() returns the master list. Core tools (BashTool, FileReadTool, FileEditTool, FileWriteTool, AgentTool, etc.) are always included. Many others are gated behind feature flags:

getTools(permissionContext) filters the master list by deny rules, REPL mode, and isEnabled(). In CLAUDE_CODE_SIMPLE mode, only BashTool, FileReadTool, and FileEditTool are available.

Tool pool assembly

assembleToolPool(permissionContext, mcpTools) is the single source of truth for the final tool set:

  1. Gets built-in tools via getTools()
  2. Filters MCP tools by deny rules
  3. Sorts each partition alphabetically for prompt cache stability (built-ins as a contiguous prefix, MCP tools as a suffix)
  4. Deduplicates with uniqBy('name') — built-ins win on name conflicts

This partitioning means adding/removing an MCP server invalidates only the MCP suffix cache, preserving the expensive built-in prefix.

Lazy loading (ToolSearch)

With 40+ built-in tools and potentially dozens of MCP tools, loading all schemas into every request is expensive. ToolSearchTool provides lazy loading: deferred tools appear by name only (no parameter schema). The model calls ToolSearch to fetch full schemas on demand. Each tool provides a searchHint (3-10 word keyword phrase) for matching.

Tool result storage

Large tool outputs are persisted to tool-results/ on disk rather than kept in memory. The maxResultSizeChars threshold (default 30,000 chars) determines when this kicks in. Maximum persisted size is 64MB. This prevents memory bloat during long sessions with hundreds of file reads.

Tool categories

Category Tools
File operations FileReadTool, FileWriteTool, FileEditTool, GlobTool, GrepTool
Execution BashTool, PowerShellTool, REPLTool
Web WebFetchTool, WebSearchTool
MCP MCPTool, ListMcpResourcesTool, ReadMcpResourceTool, McpAuthTool
Agent coordination AgentTool, TeamCreateTool, TeamDeleteTool, SendMessageTool
Task management TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, TaskStop
Session EnterPlanModeTool, ExitPlanModeTool, EnterWorktreeTool, ExitWorktreeTool
Utilities ToolSearchTool, NotebookEditTool, SleepTool, ConfigTool, BriefTool, SkillTool
Special SyntheticOutputTool (internal), RemoteTriggerTool, ScheduleCronTool

Trade-offs

  1. Parallelism vs ordering — concurrent execution is faster but results must be emitted in request order to maintain conversation coherence. The streaming tool executor handles this buffering.
  2. Lazy loading vs availability — ToolSearch reduces token cost but adds a round-trip before first use of any deferred tool.
  3. Cache preservation vs flexibility — tool registration order is locked alphabetically per partition to preserve prompt cache. This limits dynamic tool management but saves significant cost.
  4. Fail-closed defaults — new tools are assumed unsafe (not concurrent, not read-only) until explicitly marked otherwise. Safer but means new tools need explicit opt-in to parallelism.

Depends on

Key claims

Relations

Sources

src-20260409-a5fc157bc756, source code analysis of src/Tool.ts and src/tools.ts