English lecture · source-traced

Claude Code built-in tools: a panoramic inventory (source investigation notes)

Based on the actual `claude-code/src` tree (39 tool directories + testing/ + shared/). Line numbers are relative to `claude-code/src/`. Registration: `getAllBaseTools()` (`tools.ts:193-251`) is the single source of truth; about 14 core tools are enabled unconditionally, the rest are gated by `feature()` / environment variables.

EN
lecture
source
file:line
no
embellishment
中文
sibling

Based on the actual claude-code/src tree (39 tool directories + testing/ + shared/). Line numbers are relative to claude-code/src/. Registration: getAllBaseTools() (tools.ts:193-251) is the single source of truth; about 14 core tools are enabled unconditionally, the rest are gated by feature() / environment variables.

Part 1

1. File operations

Read (FileReadTool/FileReadTool.ts:338)

  • Job: read local files (text by line; images/PDFs via multimodal). The model's main "look at the code" entry. Read-only ✅ concurrency-safe ✅ enabled by default ✅
  • Parameters: file_path (absolute path, required), offset (start line), limit (line count)
  • Example: before fixing a bug, Read {file_path:"/src/index.ts", offset:100, limit:80}
  • Details: dual output caps — files >256KB are refused outright (utils/file.ts:48 MAX_OUTPUT_SIZE); output over 25000 tokens errors (limits.ts:18, overridable by env CLAUDE_CODE_FILE_READ_MAX_OUTPUT_TOKENS); maxResultSizeChars: Infinity (:342) — truncation is done in-house; comments at limits.ts:9-13 record an A/B rollback of "truncate vs error"

Edit (FileEditTool/)

  • Job: exact string replace old_string→new_string. The workhorse for editing code. Read-only ❌ concurrent ❌ default ✅
  • Parameters (types.ts:6-19): file_path, old_string, new_string, replace_all (default false)
  • Example: Edit {file_path:"…/app.ts", old_string:"const x = 1", new_string:"const x = 2"}
  • Details: read before write — a file that has not been Read errors with "File has not been read yet" (FileEditTool.ts:281); after an external change, a fresh Read is required; .ipynb is refused and the model is steered to NotebookEdit (:270)

Write (FileWriteTool/FileWriteTool.ts:95)

  • Job: write / overwrite a whole file. Parameters: file_path, content
  • Details: overwriting an existing file likewise forces "Read first"; detects "the file was changed by the user / a linter since I last read it" (:203, :216) to prevent blind overwrite

NotebookEdit (NotebookEditTool/)

  • Job: edit a Jupyter notebook cell. Parameters: notebook_path, cell_id, new_source, cell_type(code/markdown), edit_mode(replace/insert/delete)
  • Details: shouldDefer: true (:94) — delayed-loaded by ToolSearch
Part 3

3. Command execution

Bash (BashTool/BashTool.tsx:421)

  • Job: run a shell command. The model's "two hands." Default ✅
  • Parameters (:227-247): command, timeout, description (required plain-language description), run_in_background, dangerouslyDisableSandbox
  • Example: Bash {command:"npm test", description:"Run test suite"}
  • Detail 1: dynamic read-only judgment — isReadOnly(input) analyzes the command itself, parsing compounds to decide whether they are purely read-only (:434-441); preparePermissionMatcher splits ls && git push into subcommands and matches each against Bash(git *) rules (:447-465)
  • Detail 2: hidden internal field — _simulatedSedEdit is an internal field used after a sed preview is approved; it is deliberately omitted from the model-visible schema so the model cannot use it to bypass the permission sandbox and write arbitrary files (:249-259 comments); output cap 30000 characters; oversize results are persisted to disk and return persistedOutputPath (:424, :292)

PowerShell (PowerShellTool/)

  • Job: the PowerShell edition of Bash on Windows; parameters almost identical (:228-233)
  • Enablement: getPlatform()==='windows' and (ant on by default / external needs CLAUDE_CODE_USE_POWERSHELL_TOOL) (utils/shell/shellToolUtils.ts:17-22; tools.ts:242); the directory also contains gitSafety.ts, destructiveCommandWarning.ts safety checks

REPL (REPLTool/constants.ts:11)

  • Job: ant-internal "batch-operate a VM" mode: when on, the 8 primitive tools Read/Write/Edit/Glob/Grep/Bash/NotebookEdit/Agent are hidden from the model (REPL_ONLY_TOOLS :37-46); the model must call them through REPL inside the VM
  • Enablement: USER_TYPE==='ant' and the CLI entry; CLAUDE_CODE_REPL=0 can turn it off (:23-30); SDK does not enable it by default
Part 4

4. Network

WebFetch (WebFetchTool/WebFetchTool.ts)

  • Job: fetch a URL's content, then run a small prompt so the model processes that content and returns the result. Read-only ✅ shouldDefer ✅
  • Parameters: url, prompt (what to do with the fetched content)
  • Example: WebFetch {url:"https://docs…", prompt:"提取安装步骤"}
  • Details: preapproved.ts:14 maintains a "code-related domain allowlist"; only WebFetch GETs to those domains skip review. The file header is a SECURITY WARNING forbidding other tools from reusing it (:5-11)

WebSearch (WebSearchTool/WebSearchTool.ts)

  • Job: web search. Parameters: query (≥2 characters), allowed_domains, blocked_domains. shouldDefer ✅
  • Details: isEnabled() is decided by API provider — firstParty is on directly; Vertex requires a Claude 4.0+ model
Part 5

5. Sub-agents and task management

Agent (AgentTool/AgentTool.tsx:226)

  • Job: spawn a sub-agent to finish a task independently (isolated context; can run in parallel or in the background). Default ✅
  • Parameters (:82-126): description(3–5 words), prompt(the brief), subagent_type, model(sonnet/opus/haiku), run_in_background, name/team_name, mode, isolation:worktree, cwd
  • Example: three Agent {description:"调研方案A", prompt:"…", run_in_background:true} exploring in parallel
  • Details: isReadOnly()=true — Agent itself does not write disk; permission checks are all delegated to tools inside the sub-agent (:1264-1266); output cap 100000 characters (:229)

TaskOutput (TaskOutputTool/)

  • Job: read background-task output; can block and wait. Parameters: task_id, block(default true), timeout(≤600000ms, default 30000)
  • Details: read-only; isEnabled() is hard-coded "external"!=='ant' — the ant internal build actually disables it (near :163)

TaskStop (TaskStopTool/)

  • Job: terminate a background task. Parameters: task_id (compatible with the old shell_id). shouldDefer ✅ (:53)

TaskCreate / TaskGet / TaskUpdate / TaskList (TodoV2)

  • Job: structured task-list create/get/update/list; supports blocking relations addBlocks/addBlockedBy, owner, metadata; TaskUpdate status accepts 'deleted'
  • Enablement: isTodoV2Enabled() (tools.ts:218-220) — forced on in non-interactive sessions; CLAUDE_CODE_ENABLE_TASKS forces it on (utils/tasks.ts:133-139). All shouldDefer ✅

TodoWrite (TodoWriteTool/)

  • Job: classic todo-list write (content/status/activeForm)
  • Details: mutually exclusive with the TaskCreate family — isEnabled(){return !isTodoV2Enabled()} (near :51); pick one of the old and new systems
Part 6

6. Multi-agent collaboration

SendMessage (SendMessageTool/)

  • Job: send a message to a teammate agent (to supports teammate name, * broadcast; under UDS_INBOX also uds:<socket>, bridge:<session> cross-process delivery)
  • Parameters: to, summary(5–10 words UI preview), message
  • Details: isReadOnly(input) is dynamic — a pure-text message counts as read-only; isEnabled()=isAgentSwarmsEnabled()

TeamCreate / TeamDelete

  • Job: create / dissolve an agent team (TeamCreate parameters: team_name, description, agent_type)
  • Enablement: isAgentSwarmsEnabled() — always on for ant; external needs CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS or --agent-teams (utils/agentSwarmsEnabled.ts:24-32; tools.ts:228-230 lazy require to break a cyclic dependency)
Part 7

7. User interaction and configuration

AskUserQuestion (AskUserQuestionTool/AskUserQuestionTool.tsx:110)

  • Job: pop 1–4 multiple-choice questions at the user (with option annotations) and take a structured answer. Default ✅ read-only ✅ concurrent ✅
  • Parameters: questions (array of 1–4, with uniqueness-check refine)
  • Details: when --channels (Telegram/Discord) is active, isEnabled()=false — nobody is sitting at the terminal, so a dialog would hang the session (:135-145)

Brief / SendUserMessage (BriefTool/BriefTool.ts:137)

  • Job: in KAIROS (proactive assistant) mode, send a rich-text message to the user, optionally with attachments; status:proactive for a proactive push
  • Details: the directory is named Brief but the API name is SendUserMessage (prompt.ts:1); isEnabled() requires both feature('KAIROS') and a runtime entitlement (:122-135)

Skill (SkillTool/SkillTool.ts)

  • Job: invoke an installed Skill by name (inject its SKILL.md instructions). Parameters: skill, args. Example: Skill {skill:"commit"}

Config (ConfigTool/ConfigTool.ts:68)

  • Job: read/change a setting. Parameters: setting, value (omit = read)
  • Details: isReadOnly(input) is dynamic — a read with no value counts as read-only (:90-92); registered only when USER_TYPE==='ant' (tools.ts:214)
Part 8

8. Mode switching

EnterPlanMode / ExitPlanMode

  • EnterPlanMode: no parameters; enter "plan only, do not act" (EnterPlanModeTool.ts:21-26)
  • ExitPlanMode (V2 :148): submit a plan for approval; parameter allowedPrompts — declare the permission categories needed to implement the plan (describes action categories, not concrete commands); when channels are active both enter and exit tools are disabled together, to avoid "you can enter but cannot leave" (:167-178)

EnterWorktree / ExitWorktree

  • EnterWorktree: create a temporary git worktree as an isolated workspace; parameter name (slug-validated, optional)
  • ExitWorktree: action: keep|remove; isDestructive is decided from the input — only remove counts as destructive (:168-170); uncommitted changes require an explicit discard_changes:true; a session-scoped scope guard only recognizes worktrees created by this session (:177-182)
  • Enablement: isWorktreeModeEnabled() is currently always true (tools.ts:225)
Part 9

9. Scheduling and triggers

Sleep (SleepTool/prompt.ts:3)

  • Job: wait a specified duration (does not occupy a shell process; can be interrupted; the prompt recommends it over Bash(sleep), and reminds "each wake-up is one API call; the prompt cache expires in 5 minutes")
  • Enablement: feature('PROACTIVE')||feature('KAIROS') (tools.ts:25-28); the snapshot only has prompt.ts

CronCreate / CronDelete / CronList (ScheduleCronTool/)

  • Job: register a cron timed task that enqueues a prompt when due. CronCreate parameters: cron(5-field local time), prompt, recurring(false = one-shot), durable(true persists to .claude/scheduled_tasks.json across restarts)
  • Enablement: feature('AGENT_TRIGGERS') (tools.ts:29-35). All shouldDefer ✅

RemoteTrigger (RemoteTriggerTool/)

  • Job: manage remote triggers; action: list|get|create|update|run + trigger_id + body
  • Enablement: feature('AGENT_TRIGGERS_REMOTE') (tools.ts:36-38)
Part 10

10. MCP and tool discovery (important)

MCPTool wrapping

MCPTool/MCPTool.ts is a placeholder template (name:'mcp', methods annotated "Overridden in mcpClient.ts"). Real wrapping is in services/mcp/client.ts:1743-1832 fetchToolsForClient: 1. send tools/list to the MCP server 2. each tool is expanded/overridden as {...MCPTool, name: fullyQualifiedName, ...} (:1769-1773) 3. naming rule mcp__<normalize(server)>__<tool> (mcpStringUtils.ts:48); an SDK server can set CLAUDE_AGENT_SDK_MCP_NO_PREFIX to skip the prefix (:1760-1763) 4. safety metadata comes from MCP annotations: annotations.readOnlyHint→isReadOnly/isConcurrencySafe, destructiveHint→isDestructive, openWorldHint→isOpenWorld (:1795-1809); mcpInfo feeds permission rules (deny a whole server with mcp__server) 5. overlong descriptions are truncated at MAX_MCP_DESCRIPTION_LENGTH (:1789-1794); permissions default to passthrough, with a suggestion to add a localSettings allow rule

McpAuthTool (:63): when a server needs OAuth, dynamically register an mcp__<server>__authenticate tool to walk the user through authorization (client.ts:2318/2331)

ListMcpResourcesTool / ReadMcpResourceTool: list/read MCP resources (parameters server? / server+uri). Registered at the end of getAllBaseTools (tools.ts:245-246) but added on demand by getTools() as specialTools (:301-307)

ToolSearch's defer_loading mechanism

Background: too many tools explode the token cost of tool definitions. 1. Who is deferred: isDeferredTool() (ToolSearchTool/prompt.ts:62-108) — every MCP tool is deferred; 26 built-ins marked shouldDefer:true are deferred (NotebookEdit, AskUserQuestion, WebFetch, WebSearch, EnterPlanMode, ExitPlanMode, TodoWrite, TaskCreate/Get/Update/List, TaskOutput, TaskStop, SendMessage, TeamCreate/Delete, CronCreate/Delete/List, ReadMcpResource, ListMcpResources, EnterWorktree, ExitWorktree, Config, LSP, RemoteTrigger). alwaysLoad:true (MCP can exempt via _meta['anthropic/alwaysLoad'], client.ts:1785) and ToolSearch itself are never deferred 2. Modes: ENABLE_TOOL_SEARCH env — 'tst' (default, always defer), 'tst-auto' (enable only over a threshold, checkAutoThreshold utils/toolSearch.ts:444-467), 'standard' (off). Haiku does not support tool_reference and auto-degrades (:204, 239-252) 3. At request time: deferred tools are sent to the API with defer_loading:true (utils/api.ts:211-223); the model sees only a name list, no schema 4. At use time: the model calls ToolSearch {query:"select:Read,Edit"} for an exact select, or {query:"slack send"} for keywords (MCP is tokenized on mcp__server__action, built-ins on CamelCase, scored in ToolSearchTool.ts:132-216); matching items' full JSONSchema is returned wrapped in a <functions> block 5. Registration: ToolSearch is only put on the tool list if isToolSearchEnabledOptimistic() is true (tools.ts:247-249)

Part 11

11. LSP and internal/test tools

LSP (LSPTool/LSPTool.ts)

  • Job: call a language server for semantic code navigation. Parameters: operation (goToDefinition/findReferences/hover/documentSymbol/workspaceSymbol/goToImplementation/prepareCallHierarchy/incomingCalls/outgoingCalls), filePath, line, character (1-based)
  • Enablement: ENABLE_LSP_TOOL env (tools.ts:224)

StructuredOutput (SyntheticOutputTool/:20)

  • Job: in non-interactive (SDK/headless) mode, have the model emit a structured result matching a caller-supplied JSON Schema (Ajv validation)
  • Enablement: non-interactive sessions only (:24-28)

TestingPermissionTool (tools/testing/)

  • Test-only mock of the permission dialog; registered only when NODE_ENV==='test' (tools.ts:244)
Part 12

Addendum: global mechanisms

  1. Three-flag system: isReadOnly/isConcurrencySafe/isDestructive all default false (Tool.ts:750-761); may be overridden statically or dynamically from input; concurrent scheduling uses isConcurrencySafe, permission warnings use isDestructive
  2. maxResultSizeChars: Bash 30000, Grep 20000, Read Infinity, most 100000; over the cap the common pattern is "persist to disk + return persistedOutputPath"
  3. getTools() second filter (tools.ts:271-327): CLAUDE_CODE_SIMPLE minimal mode keeps only Bash/Read/Edit; deny rules strip tools from the list before the model ever sees them (filterToolsByDenyRules :262-269); REPL mode hides primitives
  4. assembleToolPool() (:345-367): merge built-ins with MCP, dedupe (built-ins win), sort each group by name, keep built-ins as a contiguous prefix — for prompt-cache stability; inserting MCP into the middle of built-ins would scramble every downstream cache key
  5. Tools cited by tools.ts but missing from the snapshot (feature-gated experiments / internal): TungstenTool, SuggestBackgroundPRTool, MonitorTool, SendUserFileTool, PushNotificationTool, SubscribePRTool, VerifyPlanExecutionTool (CLAUDE_CODE_VERIFY_PLAN=true), OverflowTestTool, CtxInspectTool, TerminalCaptureTool, WebBrowserTool, SnipTool, ListPeersTool, WorkflowTool
↑