Tool System
- Entity ID:
ent-20260410-99797a935107 - Type:
concept - Scope:
shared - Status:
active - Aliases: tool registration, tool dispatch, buildTool, tools.ts
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:
isConcurrencySafedefaults tofalse(assume not safe for parallel execution)isReadOnlydefaults tofalse(assume tool writes)isDestructivedefaults tofalsecheckPermissionsdefaults toallow(defers to the general permission system)
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:
SleepToolrequiresPROACTIVEorKAIROSflagsCronCreateTool/CronDeleteToolrequireAGENT_TRIGGERSMonitorToolrequiresMONITOR_TOOLREPLToolisant-only (internal Anthropic)- GlobTool/GrepTool are excluded when ant-native builds embed
bfs/ugrepdirectly
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:
- Gets built-in tools via
getTools() - Filters MCP tools by deny rules
- Sorts each partition alphabetically for prompt cache stability (built-ins as a contiguous prefix, MCP tools as a suffix)
- 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
- 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.
- Lazy loading vs availability — ToolSearch reduces token cost but adds a round-trip before first use of any deferred tool.
- 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.
- 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
- streaming-tool-executor — parallel execution engine
- toolsearch-system — lazy tool loading
- permission-pipeline — per-tool permission checks
- cache-economics — why registration order matters
- buildtool-factory — the factory function itself
- mcp-subsystem — external tool registration via MCP
Key claims
- Tool registration order is sorted alphabetically within partitions (built-in prefix, MCP suffix) to preserve prompt cache keys
buildTool()defaults are fail-closed: tools are assumed not concurrency-safe, not read-only until explicitly declared- In
CLAUDE_CODE_SIMPLEmode, only 3 tools are available: BashTool, FileReadTool, FileEditTool - Built-in tools win on name conflicts when deduplicating with MCP tools
Relations
depends_onstreaming-tool-executordepends_onpermission-pipelinedepends_onmcp-subsystemused_byagent-lifecyclerelated_tocache-economics
Sources
src-20260409-a5fc157bc756, source code analysis of src/Tool.ts and src/tools.ts