65 KiB
Claude Code — Tools System
Table of Contents
- Tool Framework (Tool.ts)
- Tool Registry (tools.ts)
- Task Framework (Task.ts / tasks.ts)
- Core File Tools
- Shell Execution Tools
- Search Tools
- Agent / Multi-Agent Tools
- Task Management Tools
- Web Tools
- MCP Integration Tools
- Plan Mode Tools
- Notebook Tool
- Worktree Tools
- Scheduling Tools
- Meta / Discovery Tools
- Kairos / Special Mode Tools
- SDK / Output Tools
- Skill Tool
- LSP Tool
- REPL Tool
- Config Tool
- Shared Utilities
- Testing Utilities
1. Tool Framework
Source: src/Tool.ts
1.1 Core Interface
export type Tool<Input extends ZodType = ZodType, Output = unknown, Progress = unknown> = {
// Identity
name: string
isMcp?: boolean
mcpInfo?: { serverName: string; toolName: string }
isLsp?: boolean
alwaysLoad?: boolean
shouldDefer?: boolean
// Schema (getter properties for lazy init)
readonly inputSchema: Input
readonly outputSchema?: ZodType<Output>
// Metadata
description(): Promise<string>
prompt(): Promise<string>
userFacingName(input?: z.infer<Input>): string
maxResultSizeChars?: number
searchHint?: string
// Capability flags (accept input for per-call decisions)
isEnabled(permissionContext?: ToolPermissionContext): boolean
isConcurrencySafe(input?: z.infer<Input>): boolean
isReadOnly(input?: z.infer<Input>): boolean
isDestructive?(input: z.infer<Input>): boolean
toAutoClassifierInput(input: z.infer<Input>): string
isSearchOrReadCommand?: (input: z.infer<Input>) => { isSearch: boolean; isRead: boolean }
// Execution
validateInput?(input: z.infer<Input>): Promise<ValidationResult>
checkPermissions(input: z.infer<Input>, context: ToolUseContext): Promise<PermissionDecision>
call(input: z.infer<Input>, context: ToolUseContext): Promise<ToolResult<Output>>
// UI rendering (React / Ink)
renderToolUseMessage(input: z.infer<Input>, options: RenderOptions): ReactNode | null
renderToolUseProgressMessage?(progress: Progress, input?: z.infer<Input>): ReactNode | null
renderToolUseQueuedMessage?(input: z.infer<Input>): ReactNode | null
renderToolUseRejectedMessage?(input: z.infer<Input>, ...): ReactNode | null
renderToolResultMessage(output: Output, ...): ReactNode | null
renderToolUseErrorMessage?(error: Error, ...): ReactNode | null
// Output mapping
mapToolResultToToolResultBlockParam(
output: Output,
toolUseID: string,
context: ToolUseContext,
): ToolResultBlockParam
// Path tracking (for permission rules)
getPath?(input?: z.infer<Input>): string | undefined
}
1.2 ToolDef — Definition Shape
ToolDef<Input, Output, Progress> is the shape passed to buildTool(). It has the same fields as Tool minus the defaults filled in by buildTool().
1.3 buildTool()
function buildTool<Input, Output, Progress>(def: ToolDef<Input, Output, Progress>): Tool<...>
Fills in safe defaults:
isEnabled→() => trueisConcurrencySafe→() => falseisReadOnly→() => falsecheckPermissions→async () => ({ behavior: 'allow', updatedInput: input })toAutoClassifierInput→() => ''userFacingName→() => def.name
1.4 ToolUseContext
The context object passed to every call() and checkPermissions():
type ToolUseContext = {
// Configuration
options: {
commands: Command[]
tools: Tool[]
mcpClients: MCPClient[]
mainLoopModel: string
thinkingConfig: ThinkingConfig
// ... additional options
}
// Abort signal
abortController: AbortController
// App state accessors
getAppState(): AppState
setAppState(fn: (prev: AppState) => AppState): void
// File read tracking (for read-before-write enforcement)
readFileState: Map<string, { mtime: number; content: string }>
// Permission context
permissionContext: ToolPermissionContext
// UI injection
setToolJSX: SetToolJSXFn
// Callbacks
onPermissionRequest(request: PermissionRequest): Promise<PermissionDecision>
onToolCallStart(toolName: string, input: unknown): void
onToolCallEnd(toolName: string, result: unknown): void
// Agent/teammate context
agentId?: AgentId
isSubagent?: boolean
isCoordinator?: boolean
// Additional fields for specific tool categories
globLimits?: { maxResults: number }
}
1.5 ToolPermissionContext
type ToolPermissionContext = {
mode: PermissionMode // 'default' | 'plan' | 'auto' | 'bypassPermissions' | 'acceptEdits'
alwaysAllow: PermissionRule[]
alwaysDeny: PermissionRule[]
alwaysAsk: PermissionRule[]
additionalWorkingDirectories: string[]
toolPermissions: Record<string, ToolPermissionOverride>
}
1.6 PermissionResult / PermissionDecision
type PermissionDecision =
| { behavior: 'allow'; updatedInput: Input }
| { behavior: 'ask'; message: string; decisionReason?: string }
| { behavior: 'deny'; message: string }
| { behavior: 'passthrough' } // Always asks user
type ValidationResult =
| { result: true }
| { result: false; message: string; errorCode?: number }
1.7 ToolResult
type ToolResult<T> = { data: T }
1.8 Tools Type Alias & Helpers
type Tools = Tool[]
function findToolByName(tools: Tools, name: string): Tool | undefined
function toolMatchesName(tool: Tool, name: string): boolean
2. Tool Registry
Source: src/tools.ts
2.1 getAllBaseTools()
Returns the full ordered list of built-in tools. Order must stay in sync with Statsig caching config.
function getAllBaseTools(): Tool[]
Includes (conditionally):
- Always: BashTool, GlobTool, GrepTool, FileReadTool, FileEditTool, FileWriteTool, AgentTool, WebFetchTool, WebSearchTool, NotebookEditTool, TodoWriteTool, TaskStopTool, AskUserQuestionTool, SkillTool, MCPTool, EnterPlanModeTool, ExitPlanModeV2Tool, ToolSearchTool, TaskCreateTool, TaskGetTool, TaskUpdateTool, TaskListTool, TeamCreateTool, TeamDeleteTool, SendMessageTool, TaskOutputTool, SyntheticOutputTool, EnterWorktreeTool, ExitWorktreeTool, BriefTool, RemoteTriggerTool
- Ant-only: ConfigTool, TungstenTool, REPLTool
- Feature-gated (
feature('KAIROS')+isKairosCronEnabled()): CronCreateTool, CronDeleteTool, CronListTool - Feature-gated (
feature('AGENT_TRIGGERS')): RemoteTriggerTool - Feature-gated (
feature('SLEEP_TOOL')): SleepTool - Feature-gated (
feature('MONITOR_TOOL')): MonitorMcpTask - LSP enabled: LSPTool
2.2 getTools(permissionContext)
function getTools(permissionContext: ToolPermissionContext): Tool[]
- If
CLAUDE_CODE_SIMPLEenv var is set: returns only[BashTool, FileReadTool, FileEditTool] - Calls
getAllBaseTools(), filters withfilterToolsByDenyRules() - In REPL mode: hides
REPL_ONLY_TOOLS(Bash, Read, Write, Edit, Glob, Grep, NotebookEdit, Agent)
2.3 assembleToolPool()
function assembleToolPool(
baseTools: Tool[],
mcpTools: Tool[],
): Tool[]
- Combines built-in + MCP tools
- Sorts by name for prompt-cache stability
- Deduplicates (built-in tools win over MCP tools with same name)
2.4 filterToolsByDenyRules()
function filterToolsByDenyRules(
tools: Tool[],
permissionContext: ToolPermissionContext,
): Tool[]
Removes tools whose name matches a blanket deny rule in permissionContext.
2.5 Tool Presets
const TOOL_PRESETS = {
'full': /* all tools */,
'minimal': /* BashTool, FileReadTool, FileEditTool */,
// ...
}
function parseToolPreset(preset: string): Tool[] | null
function getToolsForDefaultPreset(): Tool[]
function getMergedTools(base: Tool[], overrides: Tool[]): Tool[]
3. Task Framework
Sources: src/Task.ts, src/tasks.ts
3.1 TaskType
type TaskType =
| 'local_bash' // prefix: 'b'
| 'local_agent' // prefix: 'a'
| 'remote_agent' // prefix: 'r'
| 'in_process_teammate' // prefix: 't'
| 'local_workflow' // prefix: 'w'
| 'monitor_mcp' // prefix: 'm'
| 'dream' // prefix: 'd'
3.2 TaskStatus
type TaskStatus = 'pending' | 'running' | 'completed' | 'failed' | 'killed'
function isTerminalTaskStatus(status: TaskStatus): boolean
// Returns true for 'completed', 'failed', 'killed'
3.3 TaskStateBase
type TaskStateBase = {
id: string // prefix + 8 random base-36 chars
type: TaskType
status: TaskStatus
description: string
toolUseId?: string
startTime: number // Date.now()
endTime?: number
totalPausedMs?: number
outputFile: string // getTaskOutputPath(id)
outputOffset: number
notified: boolean
}
3.4 ID Generation
// Alphabet: '0123456789abcdefghijklmnopqrstuvwxyz'
// 36^8 ≈ 2.8 trillion combinations
function generateTaskId(type: TaskType): string
// Returns: prefix + 8 crypto-random base-36 chars
function createTaskStateBase(
id: string,
type: TaskType,
description: string,
toolUseId?: string,
): TaskStateBase
3.5 Task Interface
type Task = {
name: string
type: TaskType
kill(taskId: string, setAppState: SetAppState): Promise<void>
}
3.6 Task Registry
// src/tasks.ts
function getAllTasks(): Task[]
// Returns: [LocalShellTask, LocalAgentTask, RemoteAgentTask, DreamTask,
// optionally LocalWorkflowTask, MonitorMcpTask]
function getTaskByType(type: TaskType): Task | undefined
4. Core File Tools
4.1 FileReadTool
Tool name: Read
Source: src/tools/FileReadTool/FileReadTool.ts
Characteristics:
isConcurrencySafe: trueisReadOnly: truemaxResultSizeChars: Infinity(prevents circular reads through disk persistence)strict: truesearchHint: 'read files, images, PDFs, notebooks'isSearchOrReadCommand: { isSearch: false, isRead: true }
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
file_path |
string |
Yes | Absolute path to file |
offset |
integer |
No | Line number to start reading from |
limit |
integer |
No | Number of lines to read |
pages |
string |
No | PDF page range (e.g. "1-5", "3", "10-20"); PDF only; max 20 pages per request |
Output Schema (discriminated union on type):
// Text file
{ type: 'text'; content: string; numLines: number; startLine: number; totalLines: number }
// Image file
{ type: 'image'; base64: string; mimeType: string; originalSize: number; dimensions: { width: number; height: number } }
// Jupyter notebook
{ type: 'notebook'; cells: NotebookCell[] }
// PDF (full)
{ type: 'pdf'; base64: string; originalSize: number }
// PDF (extracted pages)
{ type: 'parts'; pages: PDFPage[] }
// Unchanged (content not modified since last read)
{ type: 'file_unchanged' }
Security / Validation:
- Blocked device paths:
/dev/zero,/dev/random,/dev/urandom,/dev/full,/dev/stdin,/dev/tty, and other infinite-stream devices - Registers file in
readFileStatecache (path →{mtime, content}) enabling FileEditTool/FileWriteTool read-before-write enforcement - UNC path handling skipped on Windows
Exports:
function registerFileReadListener(listener: FileReadListener): void
class MaxFileReadTokenExceededError extends Error
4.2 FileWriteTool
Tool name: Write
Source: src/tools/FileWriteTool/FileWriteTool.ts
Characteristics:
strict: truemaxResultSizeChars: 100_000searchHint: 'create or overwrite files'
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
file_path |
string |
Yes | Absolute path to file |
content |
string |
Yes | Full file content to write |
Output Schema:
{
type: 'create' | 'update'
filePath: string
content: string
structuredPatch: StructuredPatch
originalFile: string | null // null for new files
gitDiff?: string // Optional git diff of changes
}
Validation / Safety:
- Read-before-write enforcement: For existing files, file must appear in
readFileStatecache (must have been read with FileReadTool) - mtime staleness check: If file mtime has changed since last read, refuses to overwrite to prevent clobbering concurrent changes
- File size limit: Max 1 GiB
- UNC path security: Skips read-check for UNC paths (
\\server\share) on Windows .ipynbfiles: Redirected toNotebookEditTool- Team memory protection: Blocks writes to team memory secret files
- Deny rules: Checks permission context deny rules
- LF line endings: New content uses LF regardless of platform
- Notifies LSP client on successful edit
4.3 FileEditTool
Tool name: Edit
Source: src/tools/FileEditTool/FileEditTool.ts
Characteristics:
strict: truemaxResultSizeChars: 100_000searchHint: 'modify file contents in place'
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
file_path |
string |
Yes | Absolute path to file to edit |
old_string |
string |
Yes | Text to search for (must exist exactly once unless replace_all is true) |
new_string |
string |
Yes | Replacement text (must differ from old_string) |
replace_all |
boolean |
No (default false) |
Replace all occurrences of old_string |
Output Schema:
{
filePath: string
oldString: string
newString: string
originalFile: string // File content before edit
structuredPatch: StructuredPatch
userModified: boolean // Whether user modified the proposed diff
replaceAll: boolean
gitDiff?: string
}
Validation / Safety:
old_stringmust differ fromnew_string- File must have been read via
readFileState(read-before-write enforcement) - mtime staleness check (same as FileWriteTool)
old_stringmust be found in file content- Unless
replace_allis true, at most 1 occurrence ofold_stringis allowed - File size: max 1 GiB
- UNC path security skip
.ipynbfiles redirected toNotebookEditTool- Team memory secret guard
- Permission context deny rule check
- Uses
findActualString()for quote normalization (handles straight/curly quotes interchangeably) - Uses
preserveQuoteStyle()to maintain original quote style - Notifies LSP client on successful edit
5. Shell Execution Tools
5.1 BashTool
Tool name: Bash
Source: src/tools/BashTool/BashTool.tsx
Characteristics:
maxResultSizeChars(varies by output type)searchHint(from prompt)- Supports background task execution
- Supports sandboxing (bwrap on Linux, sandbox-exec on macOS)
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
command |
string |
Yes | Shell command to execute |
timeout |
number |
No | Timeout in milliseconds (max varies by context) |
description |
string |
No | Human-readable description of what the command does |
run_in_background |
boolean |
No | Launch as background task; omitted from schema when CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=true |
dangerouslyDisableSandbox |
boolean |
No | Override sandbox mode |
_simulatedSedEdit |
internal | — | Never in model-facing schema; used for sed edit simulation |
Output Schema:
{
stdout: string
stderr: string
interrupted: boolean
isImage?: boolean // stdout contains base64 image data
backgroundTaskId?: string // Set when run_in_background=true
backgroundedByUser?: boolean // User pressed Ctrl+B
assistantAutoBackgrounded?: boolean // Auto-backgrounded after blocking budget
dangerouslyDisableSandbox?: boolean
returnCodeInterpretation?: string // Semantic meaning of exit code
noOutputExpected?: boolean
structuredContent?: unknown
persistedOutputPath?: string // Path when output too large for inline
persistedOutputSize?: number // Total bytes when persisted
}
Timing Constants:
- Progress threshold:
2_000ms(show progress spinner after 2s) - Auto-background threshold:
120_000ms(auto-background after 2 minutes) ASSISTANT_BLOCKING_BUDGET_MS:15_000ms(in assistant/Kairos mode, auto-background after 15s in main agent)
Permission Behavior:
- Checks permission rules against the command string
bypassPermissionsmode: allows all commandsauto/acceptEditsmode: allows read-only bash commands without asking; asks for write commandsdefaultmode: always asks unless explicitly allowed
Sandbox:
- Linux:
bwrap(bubblewrap) based isolation - macOS:
sandbox-execbased isolation - Windows: no sandbox (bwrap/sandbox-exec are POSIX-only)
dangerouslyDisableSandboxoverrides per-call- Enterprise policy: if sandbox required and unavailable, execution is blocked
Blocked patterns:
detectBlockedSleepPattern(): detects baresleep Ncommands with N>=2 as first statement; suggests using SleepTool instead
Git operation tracking:
trackGitOperations()called after each bash command to fire analytics for commits, pushes, PR creationisSearchOrReadBashCommand(): classifies command for UI collapsing
Exports:
function isSearchOrReadBashCommand(command: string): { isSearch: boolean; isRead: boolean }
function detectBlockedSleepPattern(command: string): string | null
type BashToolInput = { command: string; timeout?: number; description?: string; run_in_background?: boolean; dangerouslyDisableSandbox?: boolean }
5.2 PowerShellTool
Tool name: PowerShell
Source: src/tools/PowerShellTool/PowerShellTool.tsx
Windows-native PowerShell execution tool, mirroring BashTool's interface.
Characteristics:
- Windows-specific; requires PowerShell (
pwsh) to be installed - Detects PowerShell path via
getCachedPowerShellPath() - Tracks git operations via shared
trackGitOperations() - Same sandbox policy as BashTool (POSIX sandbox applies on Linux/macOS when running
pwsh) PROGRESS_THRESHOLD_MS: 2_000msASSISTANT_BLOCKING_BUDGET_MS: 15_000ms
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
command |
string |
Yes | PowerShell command to execute |
timeout |
number |
No | Optional timeout in milliseconds (max getMaxTimeoutMs()) |
description |
string |
No | Description of what the command does |
run_in_background |
boolean |
No | Background execution; omitted when CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=true |
dangerouslyDisableSandbox |
boolean |
No | Override sandbox mode |
Output Schema:
{
stdout: string
stderr: string
interrupted: boolean
returnCodeInterpretation?: string
isImage?: boolean
persistedOutputPath?: string
persistedOutputSize?: number
backgroundTaskId?: string
backgroundedByUser?: boolean
assistantAutoBackgrounded?: boolean
}
PowerShell-specific features:
PS_SEARCH_COMMANDS:Select-String,Get-ChildItem,FindStr,where.exe(grep/find equivalents)PS_READ_COMMANDS:Get-Content,Get-Item,Test-Path,Resolve-Path,Get-Process,Get-Service,Get-ChildItem,Get-Location,Get-FileHash,Get-Acl,Format-HexPS_SEMANTIC_NEUTRAL_COMMANDS:Write-Output,Write-HostdetectBlockedSleepPattern(): catchesStart-Sleep N,Start-Sleep -Seconds N,sleep Nas first statementDISALLOWED_AUTO_BACKGROUND_COMMANDS:['start-sleep', 'sleep'](not auto-backgrounded)- Windows-native sandbox policy: if enterprise requires sandbox but Windows native, execution blocked
Exports:
export type PowerShellToolInput
function detectBlockedSleepPattern(command: string): string | null
6. Search Tools
6.1 GlobTool
Tool name: Glob
Source: src/tools/GlobTool/GlobTool.ts
Characteristics:
isConcurrencySafe: trueisReadOnly: truesearchHint: 'find files by name pattern or wildcard'isSearchOrReadCommand: { isSearch: true, isRead: false }
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
pattern |
string |
Yes | Glob pattern (e.g. "**/*.js", "src/**/*.ts") |
path |
string |
No | Directory to search in (defaults to cwd) |
Output Schema:
{
filenames: string[] // Relative to cwd
durationMs: number
numFiles: number
truncated: boolean // True if results were truncated
}
Behavior:
- Default limit: 100 files (overridable via
context.globLimits?.maxResults) - Results are sorted by modification time (most recent first)
- Paths relativized to cwd for compactness
6.2 GrepTool
Tool name: Grep
Source: src/tools/GrepTool/GrepTool.ts
Characteristics:
isConcurrencySafe: trueisReadOnly: truestrict: truemaxResultSizeChars: 20_000searchHint: 'search file contents with regex (ripgrep)'isSearchOrReadCommand: { isSearch: true }
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
pattern |
string |
Yes | Regular expression pattern |
path |
string |
No | File or directory to search |
glob |
string |
No | Glob filter (e.g. "*.js", "**/*.tsx") |
output_mode |
'content' | 'files_with_matches' | 'count' |
No (default 'files_with_matches') |
Output format |
-B |
number |
No | Lines before each match (requires output_mode: 'content') |
-A |
number |
No | Lines after each match (requires output_mode: 'content') |
-C |
number |
No | Lines before and after each match |
context |
number |
No | Alias for -C |
-n |
boolean |
No | Show line numbers (requires output_mode: 'content') |
-i |
boolean |
No | Case-insensitive search |
type |
string |
No | File type filter (e.g. "js", "py") |
head_limit |
number |
No (default 250) |
Limit output to first N lines/entries |
offset |
number |
No (default 0) |
Skip first N entries |
multiline |
boolean |
No (default false) |
Enable multiline matching (. matches newlines) |
Output Schema:
{
mode: 'content' | 'files_with_matches' | 'count'
numFiles: number
filenames: string[]
content?: string // When mode='content'
numLines?: number // When mode='content'
numMatches?: number // When mode='count'
appliedLimit?: number
appliedOffset?: number
}
Implementation Details:
- Backed by
ripgrep(rg) binary - Excludes VCS directories:
.git,.svn,.hg,.bzr,.jj,.sl max-columns: 500to prevent oversized lines- Default
head_limit: 250when unspecified
7. Agent / Multi-Agent Tools
7.1 AgentTool
Tool name: Agent (alias: Task)
Constants: AGENT_TOOL_NAME, LEGACY_AGENT_TOOL_NAME
Source: src/tools/AgentTool/AgentTool.tsx
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
description |
string |
Yes | 3-5 word description of the task |
prompt |
string |
Yes | Full task prompt for the agent |
subagent_type |
string |
No | Type of subagent to spawn |
model |
'sonnet' | 'opus' | 'haiku' |
No | Model alias for the agent |
run_in_background |
boolean |
No | Launch as background task |
name |
string |
No | Named agent for messaging |
team_name |
string |
No | Associate with this team |
mode |
string |
No | Permission mode override |
isolation |
'worktree' | 'remote' |
No | Isolation strategy |
cwd |
string |
No | Working directory (Kairos only) |
Output Schema:
Synchronous completion:
{
status: 'completed'
result: string
}
Asynchronous launch:
{
status: 'async_launched'
agentId: string
description: string
prompt: string
}
Behavior:
- Auto-backgrounds after
120_000ms - Progress shown after
2_000ms - Supports fork subagent (
subagent_type: 'fork') - Multi-agent swarm integration: when inside a team, can spawn named teammates
isolation: 'worktree'creates git worktree for isolated executionisolation: 'remote'runs in remote session
7.2 TeamCreateTool
Tool name: TeamCreate
Source: src/tools/TeamCreateTool/TeamCreateTool.ts
Gate: isAgentSwarmsEnabled()
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
team_name |
string |
Yes | Name for the team |
description |
string |
No | Team description |
agent_type |
string |
No | Default agent type for team members |
Output Schema:
{
team_name: string
team_file_path: string
lead_agent_id: string
}
Behavior:
- Creates team file at
~/.claude/teams/<team_name>.json - Resets task list to team-scoped task list
- Registers team for session cleanup (auto-cleanup on exit)
- One team per leader enforced: calling again while a team exists returns an error
7.3 TeamDeleteTool
Tool name: TeamDelete
Source: src/tools/TeamDeleteTool/TeamDeleteTool.ts
Gate: isAgentSwarmsEnabled()
Input: {} (empty object)
Output Schema:
{
success: boolean
message: string
team_name?: string
}
Behavior:
- Refuses to delete if any non-lead members have
isActive !== false(still running) - Calls
cleanupTeamDirectories(teamName)to remove team files and worktrees - Unregisters team from session cleanup
- Clears teammate color assignments
- Clears leader team name (task list falls back to session ID)
- Clears team context and inbox from app state
7.4 SendMessageTool
Tool name: SendMessage
Source: src/tools/SendMessageTool/SendMessageTool.ts
Gate: isAgentSwarmsEnabled()
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
to |
string |
Yes | Recipient: agent name, '*' (broadcast), 'uds:<path>', or 'bridge:<session-id>' |
summary |
string |
No | Short summary of message for UI |
message |
string | StructuredMessage |
Yes | Message content |
StructuredMessage union:
type StructuredMessage =
| { type: 'shutdown_request'; reason?: string }
| { type: 'shutdown_response'; status: 'ok' | 'error'; message?: string }
| { type: 'plan_approval_response'; approved: boolean; comment?: string; requestId: string }
Routing:
- In-process agents: Queues message in agent's inbox or resumes paused agent
- Mailbox (teammates): Writes to
~/.claude/mailboxes/<name>.json - UDS socket: Sends via Unix domain socket (for local inter-process)
- Bridge (cross-machine): Routes via Remote Control API; requires user safety check (not auto-approvable)
Permission: Bridge messages require user consent via decisionReason safety gate.
8. Task Management Tools
8.1 TaskStopTool
Tool name: TaskStop (alias: KillShell)
Source: src/tools/TaskStopTool/TaskStopTool.ts
Characteristics: shouldDefer: true, isConcurrencySafe: true
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
task_id |
string |
No | Task ID to stop (from background task launch) |
shell_id |
string |
No | Deprecated alias for task_id |
Output Schema:
{
message: string
task_id: string
task_type: TaskType
command?: string // For bash tasks
}
Validation:
- Task must exist in app state
- Task must be in a running (non-terminal) state
8.2 TaskOutputTool
Tool name: TaskOutput (TASK_OUTPUT_TOOL_NAME)
Source: src/tools/TaskOutputTool/TaskOutputTool.tsx
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
task_id |
string |
Yes | Task ID to read output from |
block |
boolean |
No (default true) |
Block until task completes |
timeout |
number |
No (default 30_000, range 0–600_000ms) |
Maximum wait time in ms |
Output Schema:
{
retrieval_status: 'success' | 'timeout' | 'not_ready'
task: TaskOutput | null
}
type TaskOutput = {
task_id: string
task_type: TaskType
status: TaskStatus
description: string
output: string
exitCode?: number
error?: string
prompt?: string // For agent tasks
result?: string // Final result text for agent tasks
}
8.3 TodoWriteTool (V1)
Tool name: TodoWrite
Source: src/tools/TodoWriteTool/TodoWriteTool.ts
Characteristics: strict: true, shouldDefer: true, maxResultSizeChars: 100_000
Gate: Disabled when isTodoV2Enabled()
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
todos |
TodoItem[] |
Yes | Full replacement list of todo items |
TodoItem schema:
{
id: string
content: string
status: 'pending' | 'in_progress' | 'completed'
priority: 'high' | 'medium' | 'low'
}
Output Schema:
{
oldTodos: TodoItem[]
newTodos: TodoItem[]
verificationNudgeNeeded?: boolean
}
Behavior:
- Replaces the entire todo list atomically
- Clears list automatically when all todos are completed
verificationNudgeNeeded: signals UI to nudge model to verify completed items
8.4 TaskCreateTool (V2)
Tool name: TaskCreate
Source: src/tools/TaskCreateTool/TaskCreateTool.ts
Gate: isTodoV2Enabled()
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
subject |
string |
Yes | Short task title |
description |
string |
Yes | Detailed task description |
activeForm |
object |
No | Form data for active task |
metadata |
object |
No | Arbitrary metadata |
Output Schema:
{
task: {
id: string
subject: string
}
}
Behavior:
- Runs
executeTaskCreatedHooksafter creation - Auto-expands task panel in UI
- Deletes task if hook throws an error
8.5 TaskGetTool (V2)
Tool name: TaskGet
Source: src/tools/TaskGetTool/TaskGetTool.ts
Gate: isTodoV2Enabled()
Characteristics: shouldDefer: true, isReadOnly: true
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
taskId |
string |
Yes | Task ID to retrieve |
Output Schema:
{
task: {
id: string
subject: string
description: string
status: TaskStatus
blocks: string[] // Task IDs this task blocks
blockedBy: string[] // Task IDs blocking this task
} | null
}
8.6 TaskUpdateTool (V2)
Tool name: TaskUpdate
Source: src/tools/TaskUpdateTool/TaskUpdateTool.ts
Gate: isTodoV2Enabled()
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
taskId |
string |
Yes | Task ID to update |
subject |
string |
No | Updated title |
description |
string |
No | Updated description |
activeForm |
object |
No | Updated form data |
status |
TaskStatus | 'deleted' |
No | New status; 'deleted' removes the task |
addBlocks |
string[] |
No | Task IDs this task should block |
addBlockedBy |
string[] |
No | Task IDs that block this task |
owner |
string |
No | Assign ownership |
metadata |
object |
No | Updated metadata |
Output Schema:
{
success: boolean
taskId: string
updatedFields: string[]
error?: string
statusChange?: { from: TaskStatus; to: TaskStatus | 'deleted' }
verificationNudgeNeeded?: boolean
}
Behavior:
- Runs
executeTaskCompletedHookswhen status transitions tocompleted - Auto-sets owner to calling agent on
in_progressstatus - Writes mailbox notification on owner change
verificationNudgeNeeded: set when 3+ tasks completed without a verification step
8.7 TaskListTool (V2)
Tool name: TaskList
Source: src/tools/TaskListTool/TaskListTool.ts
Gate: isTodoV2Enabled()
Characteristics: shouldDefer: true, isReadOnly: true
Input: {} (empty object)
Output Schema:
{
tasks: Array<{
id: string
subject: string
status: TaskStatus
owner?: string
blockedBy: string[] // Only non-completed blocking tasks
}>
}
Behavior:
- Filters out tasks with
_internalmetadata flag - Filters already-completed IDs from
blockedBylists
9. Web Tools
9.1 WebFetchTool
Tool name: WebFetch
Source: src/tools/WebFetchTool/WebFetchTool.ts
Characteristics: shouldDefer: true, maxResultSizeChars: 100_000
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
url |
string (URL) |
Yes | URL to fetch |
prompt |
string |
Yes | Instruction for summarizing the fetched content |
Output Schema:
{
bytes: number
code: number // HTTP status code
codeText: string
result: string // Processed/summarized content
durationMs: number
url: string
}
Permission: Per-hostname rules. Preapproved hosts bypass prompt. Rule format: domain:hostname.
Implementation:
- Converts HTML to Markdown before processing
- Applies Haiku model summarization via
applyPromptToMarkdown(prompt, markdown)when content exceeds threshold - Respects
abortControllersignal
9.2 WebSearchTool
Tool name: WebSearch
Source: src/tools/WebSearchTool/WebSearchTool.ts
Characteristics: shouldDefer: true, maxResultSizeChars: 100_000
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
query |
string (min 2 chars) |
Yes | Search query |
allowed_domains |
string[] |
No | Restrict results to these domains |
blocked_domains |
string[] |
No | Exclude results from these domains |
Output Schema:
{
query: string
results: SearchResult[] | string // String when no results or commentary
durationSeconds: number
}
type SearchResult = {
title: string
url: string
snippet: string
}
Permission: 'passthrough' — always prompts user
Implementation:
- Uses beta tool:
web_search_20250305 - Maximum 8 search operations per call
- Enabled only for
firstParty,vertex, andfoundryAPI providers
10. MCP Integration Tools
10.1 MCPTool
Tool name: mcp (overridden per server to mcp__<server>__<tool>)
Source: src/tools/MCPTool/MCPTool.ts
Characteristics:
isMcp: truemaxResultSizeChars: 100_000permission: 'passthrough'(always asks)- All methods are overridden in
mcpClient.tswhen instantiated per server
Input Schema: z.object({}).passthrough() — accepts any object
Output: string
Exports:
type MCPProgress // Re-exported from mcp progress types
10.2 McpAuthTool
Tool name: mcp__<serverName>__authenticate
Source: src/tools/McpAuthTool/McpAuthTool.ts
A pseudo-tool factory, not a standard buildTool() instance.
function createMcpAuthTool(
serverName: string,
config: ScopedMcpServerConfig,
): Tool<InputSchema, McpAuthOutput>
Input: {} (empty)
Output Schema:
type McpAuthOutput = {
status: 'auth_url' | 'unsupported' | 'error'
message: string
authUrl?: string // Present when status='auth_url'
}
Behavior:
- Created for MCP servers that are installed but need OAuth authentication
- Starts
performMCPOAuthFlow()withskipBrowserOpen: true - Returns authorization URL for user to open in browser
- Background continuation: when OAuth completes, calls
reconnectMcpServerImpl()and swaps real tools into app state via prefix-based replacement claudeai-proxytransport: returns'unsupported'and directs user to/mcp- Silent auth (cached IdP token): returns success message without URL
10.3 ListMcpResourcesTool
Tool name: mcp__listResources (LIST_MCP_RESOURCES_TOOL_NAME)
Source: src/tools/ListMcpResourcesTool/ListMcpResourcesTool.ts
Characteristics: shouldDefer: true
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
server |
string |
No | Filter by server name |
Output Schema:
Array<{
uri: string
name: string
mimeType?: string
description?: string
server: string
}>
Note: Not included in getTools() directly; only added when MCP servers with resources are present.
10.4 ReadMcpResourceTool
Tool name: ReadMcpResourceTool
Source: src/tools/ReadMcpResourceTool/ReadMcpResourceTool.ts
Characteristics: shouldDefer: true
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
server |
string |
Yes | MCP server name |
uri |
string |
Yes | Resource URI to read |
Output Schema:
{
contents: Array<{
uri: string
mimeType?: string
text?: string
blobSavedTo?: string // Path when binary blob saved to disk
}>
}
Implementation:
- Binary blobs are saved to disk;
getBinaryBlobSavedMessage()returns path reference string
11. Plan Mode Tools
11.1 EnterPlanModeTool
Tool name: EnterPlanMode
Source: src/tools/EnterPlanModeTool/EnterPlanModeTool.ts
Characteristics: shouldDefer: true, maxResultSizeChars: 100_000, isConcurrencySafe: true, isReadOnly: true
Input: {} (empty object)
Output Schema:
{
message: string // Confirmation message
}
Behavior:
- Sets permission mode to
'plan'(read-only planning mode) - Disabled with
--channelsflag - Cannot be called from agent (teammate) context; only from main agent
- Saves current permission mode as
prePlanModefor restoration byExitPlanMode
11.2 ExitPlanModeV2Tool
Tool name: ExitPlanMode (EXIT_PLAN_MODE_V2_TOOL_NAME)
Source: src/tools/ExitPlanModeTool/ExitPlanModeV2Tool.ts
Characteristics: shouldDefer: true, maxResultSizeChars: 100_000
Input Schema (model-facing):
| Parameter | Type | Required | Description |
|---|---|---|---|
allowedPrompts |
AllowedPrompt[] |
No | Pre-approved tool calls (passthrough schema) |
AllowedPrompt:
{
tool: 'Bash'
prompt: string
}
SDK Input Schema (adds):
| Parameter | Type | Required | Description |
|---|---|---|---|
plan |
string |
No | Plan text for SDK mode |
planFilePath |
string |
No | Path to plan file for SDK mode |
Output Schema:
type Output = {
plan: string
isAgent: boolean
filePath?: string
hasTaskTool?: boolean
planWasEdited?: boolean
awaitingLeaderApproval?: boolean
requestId?: string
}
Behavior:
- For teammates with
isPlanModeRequired(): sendsplan_approval_requestmessage to team-lead's mailbox; returnsawaitingLeaderApproval: truewith arequestId - For non-teammates: restores permission mode to
prePlanMode(typicallydefaultorauto) - Disabled with
--channelsflag
Exports:
type AllowedPrompt
const _sdkInputSchema // Extended schema with plan/planFilePath
type Output
12. Notebook Tool
NotebookEditTool
Tool name: NotebookEdit
Source: src/tools/NotebookEditTool/NotebookEditTool.ts
Characteristics: shouldDefer: true, maxResultSizeChars: 100_000
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
notebook_path |
string |
Yes | Absolute path to .ipynb file |
cell_id |
string |
No | Target cell ID (required for edit/delete; omit for new cell) |
new_source |
string |
Yes | New source content for the cell |
cell_type |
'code' | 'markdown' |
No | Cell type (for new cells) |
edit_mode |
'replace' | 'insert' | 'delete' |
No (default 'replace') |
Edit operation |
Output Schema:
{
new_source: string
cell_id?: string
cell_type: 'code' | 'markdown'
language: string
edit_mode: 'replace' | 'insert' | 'delete'
error?: string
notebook_path: string
original_file: string // Full notebook JSON before edit
updated_file: string // Full notebook JSON after edit
}
Validation / Safety:
- Read-before-write required (same as FileEditTool/FileWriteTool)
- mtime staleness check
- UNC path security skip
- Clears
execution_countandoutputson cell replace (avoids stale output display)
13. Worktree Tools
13.1 EnterWorktreeTool
Tool name: EnterWorktree (ENTER_WORKTREE_TOOL_NAME)
Source: src/tools/EnterWorktreeTool/EnterWorktreeTool.ts
Characteristics: shouldDefer: true, maxResultSizeChars: 100_000
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
name |
string |
No | Optional name for the worktree. Each /-separated segment: letters, digits, dots, underscores, dashes only; max 64 chars total. Random name generated if not provided. |
Output Schema:
{
worktreePath: string
worktreeBranch?: string
message: string
}
Behavior:
- Validates not already in a worktree session created by this session
- Resolves to main repo root before creating worktree
- Calls
createWorktreeForSession(sessionId, slug)to create git worktree (or hooks-based worktree) - Updates
cwd,originalCwdto worktree path - Clears system prompt sections cache (so
env_info_simplerecomputes with worktree context) - Clears memoized caches that depend on cwd
- Logs
tengu_worktree_createdanalytics event
13.2 ExitWorktreeTool
Tool name: ExitWorktree (EXIT_WORKTREE_TOOL_NAME)
Source: src/tools/ExitWorktreeTool/ExitWorktreeTool.ts
Characteristics: shouldDefer: true, maxResultSizeChars: 100_000
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
action |
'keep' | 'remove' |
Yes | 'keep' preserves worktree and branch on disk; 'remove' deletes both |
discard_changes |
boolean |
No | Required true when action='remove' and worktree has uncommitted files or unmerged commits |
Output Schema:
{
action: 'keep' | 'remove'
originalCwd: string
worktreePath: string
worktreeBranch?: string
tmuxSessionName?: string
discardedFiles?: number // Set when action='remove'
discardedCommits?: number // Set when action='remove'
message: string
}
Validation:
- Only operates on worktrees created by
EnterWorktreeToolin the current session (scope guard viagetCurrentWorktreeSession()) - When
action='remove'withoutdiscard_changes: true:- Runs
countWorktreeChanges(): usesgit status --porcelain+git rev-list --count <originalHead>..HEAD - Returns error listing uncommitted files and unmerged commits
- Returns error if git state cannot be determined (fail-closed)
- Runs
Behavior:
action='keep': callskeepWorktree(), restores session to original cwd, preserves worktree for later useaction='remove': kills tmux session if any, callscleanupWorktree()(removes worktree and branch), restores session- Both actions: restore
cwd,originalCwd, optionallyprojectRoot, clear caches - Logs
tengu_worktree_keptortengu_worktree_removedanalytics events
14. Scheduling Tools
These tools are gated by isKairosCronEnabled() (requires feature('KAIROS') + GB gate).
14.1 CronCreateTool
Tool name: CronCreate (CRON_CREATE_TOOL_NAME)
Source: src/tools/ScheduleCronTool/CronCreateTool.ts
Characteristics: shouldDefer: true, maxResultSizeChars: 100_000
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
cron |
string |
Yes | Standard 5-field cron expression in local time: "M H DoM Mon DoW" |
prompt |
string |
Yes | Prompt to enqueue at each fire time |
recurring |
boolean |
No (default true) |
true = fire on every cron match (auto-expires after DEFAULT_MAX_AGE_DAYS days); false = fire once then auto-delete |
durable |
boolean |
No (default false) |
true = persist to .claude/scheduled_tasks.json and survive restarts; false = in-memory only, dies when session ends |
Output Schema:
{
id: string // Job ID for reference in CronDelete/CronList
humanSchedule: string // Human-readable schedule (e.g. "Every 5 minutes")
recurring: boolean
durable?: boolean
}
Validation:
- Valid 5-field cron expression required
- Expression must match at least one calendar date within the next year
- Maximum 50 concurrent scheduled jobs
- Durable crons not supported for teammates (teammates don't persist across sessions)
Constants:
MAX_JOBS: 50DEFAULT_MAX_AGE_DAYS: defined in prompt.ts
14.2 CronDeleteTool
Tool name: CronDelete (CRON_DELETE_TOOL_NAME)
Source: src/tools/ScheduleCronTool/CronDeleteTool.ts
Characteristics: shouldDefer: true, maxResultSizeChars: 100_000
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
id |
string |
Yes | Job ID returned by CronCreate |
Output Schema:
{
id: string // Cancelled job ID
}
Validation:
- Job with given ID must exist
- Teammates may only delete their own cron jobs (ownership enforced by
agentId)
14.3 CronListTool
Tool name: CronList (CRON_LIST_TOOL_NAME)
Source: src/tools/ScheduleCronTool/CronListTool.ts
Characteristics: shouldDefer: true, isConcurrencySafe: true, isReadOnly: true, maxResultSizeChars: 100_000
Input: {} (empty object)
Output Schema:
{
jobs: Array<{
id: string
cron: string
humanSchedule: string
prompt: string
recurring?: boolean
durable?: boolean
}>
}
Behavior:
- Teammates only see their own cron jobs (filtered by
agentId) - Team lead (no teammate context) sees all jobs
15. Meta / Discovery Tools
15.1 ToolSearchTool
Tool name: ToolSearch (TOOL_SEARCH_TOOL_NAME)
Source: src/tools/ToolSearchTool/ToolSearchTool.ts
Characteristics: maxResultSizeChars: 100_000, isConcurrencySafe: true, isReadOnly: true
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
query |
string |
Yes | select:<name> for exact tool lookup by name, or keywords for fuzzy search |
max_results |
number |
No (default 5) |
Maximum number of tools to return |
Output Schema:
{
matches: string[] // Tool names that matched
query: string
total_deferred_tools: number
pending_mcp_servers?: string[] // MCP servers still loading
}
Scoring algorithm:
| Match type | Built-in score | MCP score |
|---|---|---|
| Exact name part match | 10 | 12 |
| Substring in name | 5 | 6 |
Word boundary in searchHint |
4 | — |
| Match in description | 2 | — |
Behavior:
select:<name>prefix: exact name lookup, fetches full schema definition- Keywords: fuzzy scoring across all deferred tools
mapToolResultToToolResultBlockParam: returnstool_referenceblocks for matched tools (injects their schemas into context)
Exports:
function clearToolSearchDescriptionCache(): void
15.2 AskUserQuestionTool
Tool name: AskUserQuestion (ASK_USER_QUESTION_TOOL_NAME)
Source: src/tools/AskUserQuestionTool/AskUserQuestionTool.tsx
Characteristics: shouldDefer: true, maxResultSizeChars: 100_000, requiresUserInteraction: true
Input Schema (model-facing):
| Parameter | Type | Required | Description |
|---|---|---|---|
questions |
Question[] |
Yes | 1–4 questions to ask the user |
answers |
object |
No | Injected by UI after user responds (not in model-facing schema) |
annotations |
object |
No | Metadata annotations |
metadata |
object |
No | Arbitrary metadata |
Question schema:
{
question: string
header?: string
options: QuestionOption[] // 2-4 options
multiSelect?: boolean
}
type QuestionOption = {
label: string
value: string
description?: string
}
Output Schema:
{
questions: Question[]
answers: Record<string, string | string[]> // question → answer(s)
annotations?: object
}
Behavior:
- Disabled when
--channelsflag is active (no terminal for dialog) - UI renders interactive question dialog;
answersfield is injected by UI layer - Supports single-select and multi-select question types
Exports:
const _sdkInputSchema // Full input schema including answers field
const _sdkOutputSchema // Full output schema
type Question
type QuestionOption
16. Kairos / Special Mode Tools
16.1 BriefTool (SendUserMessage)
Tool name: SendUserMessage (BRIEF_TOOL_NAME, alias: LEGACY_BRIEF_TOOL_NAME)
Source: src/tools/BriefTool/BriefTool.ts
Gate: isBriefEnabled() — requires feature('KAIROS') or feature('KAIROS_BRIEF') + Growthbook gate + userMsgOptIn or kairosActive
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
message |
string (markdown) |
Yes | Message to send to the user |
attachments |
string[] |
No | File paths to attach |
status |
'normal' | 'proactive' |
Yes | Message disposition: 'proactive' for unsolicited updates |
Output Schema:
type Output = {
message: string
attachments?: Array<{
path: string
size: number
isImage: boolean
file_uuid: string
}>
sentAt?: string // ISO timestamp
}
Exports:
function isBriefEntitled(): boolean // Has the entitlement
function isBriefEnabled(): boolean // Has entitlement AND feature flags on
type Output
16.2 SleepTool
Tool name: Sleep
Source: src/tools/SleepTool/ (only prompt.ts present; tool implementation loaded via require() when feature('SLEEP_TOOL'))
Gate: feature('SLEEP_TOOL') feature flag
Purpose: Wait for a specified duration without holding a shell process. Can be interrupted by the user.
Prompt highlights:
- Use when user says to sleep/rest, when waiting for something, or when nothing to do
- Can be called concurrently with other tools
- Prefer over
Bash(sleep ...)— doesn't hold a shell process - Receives periodic
<tick>prompts during sleep; check for useful work before sleeping - Each wake-up costs an API call; prompt cache expires after 5 minutes of inactivity
16.3 RemoteTriggerTool
Tool name: RemoteTrigger (REMOTE_TRIGGER_TOOL_NAME)
Source: src/tools/RemoteTriggerTool/RemoteTriggerTool.ts
Gate: feature('AGENT_TRIGGERS') + getFeatureValue_CACHED_MAY_BE_STALE('tengu_surreal_dali', false) + isPolicyAllowed('allow_remote_sessions')
Characteristics: shouldDefer: true, maxResultSizeChars: 100_000, isConcurrencySafe: true
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
action |
'list' | 'get' | 'create' | 'update' | 'run' |
Yes | CRUD operation on triggers |
trigger_id |
string |
No | Required for get, update, run (regex: [\w-]+) |
body |
Record<string, unknown> |
No | JSON body for create and update |
Output Schema:
{
status: number // HTTP status code
json: string // Serialized response body
}
Implementation:
- Calls
${BASE_API_URL}/v1/code/triggersREST API - Uses OAuth token (
checkAndRefreshOAuthTokenIfNeeded()+getClaudeAIOAuthTokens()) - Requires org UUID (
getOrganizationUUID()) - API beta header:
ccr-triggers-2026-01-30 - Timeout:
20_000ms isReadOnly:trueforlistandgetactions;falseotherwise
17. SDK / Output Tools
17.1 SyntheticOutputTool (StructuredOutput)
Tool name: StructuredOutput
Source: src/tools/SyntheticOutputTool/SyntheticOutputTool.ts
Gate: Enabled only in non-interactive sessions (SDK / --output-format json mode)
Input: Passthrough — any object, validated against the provided JSON schema via AJV
Output: 'Structured output provided successfully' (string)
Factory:
function createSyntheticOutputTool(jsonSchema: object): Tool
- Creates a validated instance with
WeakMapcaching (same schema object returns same tool) - Used in SDK/
--output-format jsonmode to force the model to emit a structured final response - AJV validation ensures output matches the caller-provided JSON schema
18. Skill Tool
Tool name: Skill (SKILL_TOOL_NAME)
Source: src/tools/SkillTool/SkillTool.ts
Characteristics: maxResultSizeChars: 100_000
Purpose: Runs prompt commands (skills) defined in local files or MCP skill servers.
Exports:
type Progress // Re-export of SkillToolProgress
19. LSP Tool
Tool name: LSP (LSP_TOOL_NAME)
Source: src/tools/LSPTool/LSPTool.ts
Gate: ENABLE_LSP_TOOL=true environment variable
Characteristics: isLsp: true
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
operation |
string |
Yes | One of: goToDefinition, findReferences, hover, documentSymbol, workspaceSymbol, goToImplementation, prepareCallHierarchy, incomingCalls, outgoingCalls |
filePath |
string |
Yes | Absolute path to file |
line |
number |
Yes | 1-based line number |
character |
number |
Yes | 1-based character position |
Constraints:
- Max file size: 10 MB
20. REPL Tool
Tool name: REPL
Source: src/tools/REPLTool/
Gate: Ant-only (USER_TYPE === 'ant') + loaded via require()
Constants (src/tools/REPLTool/constants.ts):
const REPL_TOOL_NAME = 'REPL'
function isReplModeEnabled(): boolean
// true when: CLAUDE_CODE_REPL not falsy AND (CLAUDE_REPL_MODE=1 OR (USER_TYPE='ant' AND CLAUDE_CODE_ENTRYPOINT='cli'))
// SDK entrypoints default to REPL mode OFF
const REPL_ONLY_TOOLS = new Set([
'Read', 'Write', 'Edit', 'Glob', 'Grep', 'Bash', 'NotebookEdit', 'Agent',
])
// Hidden from model in REPL mode; model must use REPL for batch operations
Primitive Tools (src/tools/REPLTool/primitiveTools.ts):
function getReplPrimitiveTools(): readonly Tool[]
// Returns: [FileReadTool, FileWriteTool, FileEditTool, GlobTool, GrepTool, BashTool, NotebookEditTool, AgentTool]
// Lazy getter to avoid TDZ circular dependency
// These tools remain accessible inside REPL VM context even when hidden from model
21. Config Tool
Tool name: Config (CONFIG_TOOL_NAME)
Source: src/tools/ConfigTool/ConfigTool.ts
Gate: Ant-only
Characteristics: shouldDefer: true, maxResultSizeChars: 100_000
Input Schema:
| Parameter | Type | Required | Description |
|---|---|---|---|
setting |
string |
Yes | Configuration key (e.g. "theme", "model") |
value |
string | boolean | number |
No | New value (omit for GET operation) |
Output Schema:
{
success: boolean
operation?: 'get' | 'set'
setting?: string
value?: unknown
previousValue?: unknown
newValue?: unknown
error?: string
}
Permission:
- GET operations: auto-allow
- SET operations: requires user permission prompt
Sources: Settings can come from 'global' config or 'settings' config.
Exports:
type Input
type Output
22. Shared Utilities
22.1 tools/utils.ts
/**
* Tags user messages with a sourceToolUseID so they stay transient
* until the tool resolves. Prevents "is running" message duplication in UI.
*/
function tagMessagesWithToolUseID(
messages: (UserMessage | AttachmentMessage | SystemMessage)[],
toolUseID: string | undefined,
): (UserMessage | AttachmentMessage | SystemMessage)[]
/**
* Extracts the tool use ID from a parent message for a given tool name.
*/
function getToolUseIDFromParentMessage(
parentMessage: AssistantMessage,
toolName: string,
): string | undefined
22.2 tools/shared/gitOperationTracking.ts
Shell-agnostic git operation tracking for usage metrics. Works identically for BashTool and PowerShellTool.
Exported Types:
type CommitKind = 'committed' | 'amended' | 'cherry-picked'
type BranchAction = 'merged' | 'rebased'
type PrAction = 'created' | 'edited' | 'merged' | 'commented' | 'closed' | 'ready'
Key Functions:
/**
* Scan command + output for git operations worth surfacing in UI summary.
* Detects: git commit, git push, git merge, git rebase, gh pr *, glab mr create, curl PR APIs.
*/
function detectGitOperation(
command: string,
output: string,
): {
commit?: { sha: string; kind: CommitKind }
push?: { branch: string }
branch?: { ref: string; action: BranchAction }
pr?: { number: number; url?: string; action: PrAction }
}
/**
* Fire analytics events and OTLP counters for git operations.
* Called after each Bash/PowerShell command completes (exit code 0 only).
*/
function trackGitOperations(
command: string,
exitCode: number,
stdout?: string,
): void
// Exported for testing
function parseGitCommitId(stdout: string): string | undefined
Detected operations:
git commit→tengu_git_operation{operation: 'commit'}, increments commit OTLP countergit commit --amend→ additionally firestengu_git_operation{operation: 'commit_amend'}git push→tengu_git_operation{operation: 'push'}gh pr create/edit/merge/comment/close/ready→tengu_git_operation{operation: 'pr_<action>'}, creates fires PR OTLP counter + links session to PR URLglab mr create→tengu_git_operation{operation: 'pr_create'}, increments PR OTLP countercurl POSTto PR endpoints →tengu_git_operation{operation: 'pr_create'}
Git command regex: Tolerates global options between git and subcommand (e.g. git -c commit.gpgsign=false commit).
22.3 tools/shared/spawnMultiAgent.ts
Shared module for teammate/subagent creation, extracted from TeammateTool for reuse by AgentTool.
Key functions:
// Internal helper
function getDefaultTeammateModel(leaderModel: string | null): string
// Checks globalConfig.teammateDefaultModel; null → follow leader; undefined → use hardcoded fallback
Backend types:
in-process: Spawns teammate as in-process coroutine (no external process)- Tmux-based pane: Spawns in new tmux pane within swarm session
- External process backends
Detection:
detectAndGetBackend(): Probes available backendsisInProcessEnabled(): Checks if in-process spawning is availableisTmuxAvailable(): Checks tmux availability for pane backend
Environment inheritance:
buildInheritedEnvVars(): Builds environment variable set for spawned teammate- Key env vars propagated:
TEAMMATE_COMMAND_ENV_VAR, model overrides, plugin paths, etc.
23. Testing Utilities
TestingPermissionTool
Tool name: TestingPermission
Source: src/tools/testing/TestingPermissionTool.tsx
Gate: Only enabled when NODE_ENV === 'test' (hardcoded: "production" === 'test' → always disabled in production)
export const TestingPermissionTool: Tool<InputSchema, string>
Input: {} (empty object)
Output: 'TestingPermission executed successfully'
Behavior:
- Always returns
{ behavior: 'ask', message: 'Run test?' }fromcheckPermissions() - Used for end-to-end permission dialog testing
- All render functions return
null isConcurrencySafe: true,isReadOnly: true- Never appears in production tool list (disabled at build time)
Appendix: Tool Name Constants
| Constant | Value | Source |
|---|---|---|
BASH_TOOL_NAME |
'Bash' |
BashTool/toolName.ts |
FILE_READ_TOOL_NAME |
'Read' |
FileReadTool/prompt.ts |
FILE_WRITE_TOOL_NAME |
'Write' |
FileWriteTool/prompt.ts |
FILE_EDIT_TOOL_NAME |
'Edit' |
FileEditTool/constants.ts |
GLOB_TOOL_NAME |
'Glob' |
GlobTool/prompt.ts |
GREP_TOOL_NAME |
'Grep' |
GrepTool/prompt.ts |
AGENT_TOOL_NAME |
'Agent' |
AgentTool/constants.ts |
LEGACY_AGENT_TOOL_NAME |
'Task' |
AgentTool/constants.ts |
NOTEBOOK_EDIT_TOOL_NAME |
'NotebookEdit' |
NotebookEditTool/constants.ts |
TASK_OUTPUT_TOOL_NAME |
'TaskOutput' |
TaskOutputTool/ |
ASK_USER_QUESTION_TOOL_NAME |
'AskUserQuestion' |
AskUserQuestionTool/ |
SKILL_TOOL_NAME |
'Skill' |
SkillTool/ |
TOOL_SEARCH_TOOL_NAME |
'ToolSearch' |
ToolSearchTool/ |
CONFIG_TOOL_NAME |
'Config' |
ConfigTool/ |
BRIEF_TOOL_NAME |
'SendUserMessage' |
BriefTool/ |
SLEEP_TOOL_NAME |
'Sleep' |
SleepTool/prompt.ts |
REMOTE_TRIGGER_TOOL_NAME |
(from prompt.ts) |
RemoteTriggerTool/prompt.ts |
ENTER_WORKTREE_TOOL_NAME |
(from constants.ts) |
EnterWorktreeTool/constants.ts |
EXIT_WORKTREE_TOOL_NAME |
(from constants.ts) |
ExitWorktreeTool/constants.ts |
TEAM_DELETE_TOOL_NAME |
(from constants.ts) |
TeamDeleteTool/constants.ts |
CRON_CREATE_TOOL_NAME |
(from prompt.ts) |
ScheduleCronTool/prompt.ts |
CRON_DELETE_TOOL_NAME |
(from prompt.ts) |
ScheduleCronTool/prompt.ts |
CRON_LIST_TOOL_NAME |
(from prompt.ts) |
ScheduleCronTool/prompt.ts |
EXIT_PLAN_MODE_V2_TOOL_NAME |
'ExitPlanMode' |
ExitPlanModeTool/ |
LIST_MCP_RESOURCES_TOOL_NAME |
'mcp__listResources' |
ListMcpResourcesTool/ |
POWERSHELL_TOOL_NAME |
'PowerShell' |
PowerShellTool/toolName.ts |
REPL_TOOL_NAME |
'REPL' |
REPLTool/constants.ts |
LSP_TOOL_NAME |
'LSP' |
LSPTool/ |
Appendix: Tool Feature Gates Summary
| Tool | Gate / Condition |
|---|---|
ConfigTool, REPLTool |
USER_TYPE === 'ant' |
CronCreate/Delete/List |
feature('KAIROS') + isKairosCronEnabled() GB gate |
SleepTool |
feature('SLEEP_TOOL') |
RemoteTriggerTool |
feature('AGENT_TRIGGERS') + tengu_surreal_dali GB flag + allow_remote_sessions policy |
BriefTool |
feature('KAIROS') or feature('KAIROS_BRIEF') + GB gate + userMsgOptIn or kairosActive |
TeamCreate/Delete, SendMessage |
isAgentSwarmsEnabled() |
TaskCreate/Get/Update/List |
isTodoV2Enabled() |
TodoWriteTool |
!isTodoV2Enabled() |
LSPTool |
ENABLE_LSP_TOOL=true env var |
TestingPermissionTool |
NODE_ENV === 'test' (always disabled in production) |
MonitorMcpTask |
feature('MONITOR_TOOL') |
LocalWorkflowTask |
feature('WORKFLOW_SCRIPTS') |
Appendix: deferred vs. alwaysLoad
Tools with shouldDefer: true are hidden from the initial prompt context to save tokens. The model discovers them via ToolSearchTool using keyword search or select:<name> queries. ToolSearchTool injects tool_reference blocks for matched tools, which causes the tool schemas to be loaded into context.
Tools with alwaysLoad: true are always included even in contexts where deferral is the default.
Tools without either flag are included in the initial prompt by default.