InkdownInkdown
Start writing

Claude-Code

62 files·4 subfolders

Shared Workspace

Claude-Code
codex

04-tools-system

Shared from "Claude-Code" on Inkdown

Tools System Architecture

Overview

Tools are how Claude interacts with the world. Every action - reading files, running commands, searching code - is a tool. The tool system is modular, type-safe, and extensible.

Plain text
┌─────────────────────────────────────────────────────────────────────────────┐
│                           TOOL SYSTEM                                        │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌──────────────┐    ┌──────────────┐    ┌──────────────┐                │
│  │   Tool       │───►│   Input      │───►│  Execution   │                │
│  │   Definition │    │   Validation │    │  & UI        │                │
│  │   (Zod)      │    │   (Zod)      │    │              │                │
│  └──────────────┘    └──────────────┘    └──────────────┘                │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐ │
│  │                        BUILT-IN TOOLS                               │ │
│  │  ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐      │ │
│  │  │  Bash  │ │ File   │ │ File   │ │  Glob  │ │  Grep  │ │  Web   │      │ │
│  │  │  Tool  │ │ Read   │ │ Edit   │ │  Tool  │ │  Tool  │ │ Search │      │ │
│  │  └────────┘ └────────┘ └────────┘ └────────┘ └────────┘ └────────┘      │ │
│  │  ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐      │ │
│  │  │ Agent  │ │ Task   │ │ LSP    │ │  MCP   │ │  Todo  │ │ Config │      │ │
│  │  │  Tool  │ │ Tools  │ │  Tool  │ │  Tool  │ │  Tool  │ │  Tool  │      │ │
│  │  └────────┘ └────────┘ └────────┘ └────────┘ └────────┘ └────────┘      │ │
│  └─────────────────────────────────────────────────────────────────────┘ │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐ │
│  │                      EXTERNAL TOOLS (MCP)                           │ │
│  │           ┌──────────┐  ┌──────────┐  ┌──────────┐                   │ │
│  │           │ Postgres │  │  GitHub  │  │  Custom  │                   │ │
│  │           │  Server  │  │  Server  │  │  Servers │                   │ │
│  │           └──────────┘  └──────────┘  └──────────┘                   │ │
│  └─────────────────────────────────────────────────────────────────────┘ │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘
0000_start_here_index_and_recommended_reading_order.md
0100_project_overview_tech_stack_runtime_modes_and_folder_map.md
0200_startup_flow_entry_points_and_cold_start_sequence.md
0300_codebase_modules_layers_state_models_and_schemas.md
0400_system_architecture_and_design_rationale.md
0500_interactive_repl_request_flow_end_to_end.md
0600_headless_sdk_and_print_mode_request_flow_end_to_end.md
0700_mcp_integration_connection_and_tool_call_flow.md
0800_external_services_sdks_storage_and_local_dependencies.md
0900_environment_variables_settings_feature_flags_and_failure_modes.md
1000_non_obvious_patterns_gotchas_and_debugging_traps.md
1100_full_codebase_file_inventory_grouped_by_directory.md
kimi
00-overview.md
01-entrypoints.md
02-state-management.md
03-query-system.md
04-tools-system.md
05-tasks-system.md
06-ui-components.md
07-bridge-remote.md
08-services.md
09-skills-plugins.md
10-commands.md
11-testing-architecture.md
12-permission-system.md
13-build-system.md
14-ink-internals.md
15-git-internals.md
16-context-compaction.md
17-vim-mode.md
18-mailbox-notifications.md
19-session-persistence.md
20-hooks-system.md
21-error-recovery.md
README.md
qwen
00-overview.md
01-entry-points.md
02-query-engine.md
03-tools-and-tasks.md
04-commands-and-skills.md
05-state-management.md
06-ink-rendering.md
07-bridge-remote.md
08-mcp-services.md
09-services-overview.md
10-multi-agent.md
11-system-prompt-constants.md
12-tool-interface.md
13-memory-system.md
14-buddy-companion.md
15-keybindings.md
16-stop-hooks.md
17-vim-mode.md
18-upstreamproxy.md
19-cost-tracking-history.md
20-contexts-styles-onboarding.md
21-hooks.md
22-screens.md
tweets-explain
claude-code-memory-analysis.md
compact
memory-system
agentic-architecture

Core Files

FilePurpose
Tool.tsBase Tool type definitions
tools.tsTool registry and getAllBaseTools()
tools/[Name]Tool/[Name]Tool.tsIndividual tool implementations
tools/[Name]Tool/prompt.tsTool descriptions for LLM
tools/[Name]Tool/UI.tsxTool-specific UI components
tools/[Name]Tool/constants.tsTool constants

Tool Interface

Every tool implements this interface:

TypeScript
// Tool.ts
export type Tool = {
  // Identification
  name: string
  description: string
  descriptionForAssistant: string  // Detailed version for LLM

  // Input schema (Zod)
  inputJSONSchema: ToolInputJSONSchema
  inputSchema: z.ZodSchema<unknown>

  // Execution
  async execute(
    input: unknown,
    context: ToolUseContext
  ): Promise<ToolResult>

  // Optional: Progress tracking
  isProgress Aware?: boolean

  // Optional: Custom UI
  renderUI?(args: ToolUIArgs): React.ReactNode

  // Optional: Enable check
  isEnabled?(): boolean

  // Permission level
  permissionLevel: 'background' | 'user' | 'dangerous'
}

Tool Anatomy

1. Definition
TypeScript
// tools/BashTool/BashTool.ts
export const BashTool: Tool = {
  name: 'Bash',
  description: 'Execute bash commands',
  descriptionForAssistant: `Execute shell commands in the current working directory.
  Use this for file operations, git commands, building, testing, etc.`,

  // JSON Schema for LLM
  inputJSONSchema: {
    type: 'object',
    properties: {
      command: {
        type: 'string',
        description: 'The bash command to execute',
      },
      timeout: {
        type: 'number',
        description: 'Timeout in milliseconds',
      },
    },
    required: ['command'],
  },

  // Zod schema for runtime validation
  inputSchema: z.object({
    command: z.string(),
    timeout: z.number().optional(),
  }),

  // Execution logic
  async execute(input, context) {
    const { command, timeout } = input as BashInput
    const result = await executeCommand(command, { timeout })
    return {
      type: 'tool_result',
      content: result.output,
      is_error: result.exitCode !== 0,
    }
  },

  // Permission level
  permissionLevel: 'dangerous',  // Requires user approval
}
2. Prompt (LLM Description)
TypeScript
// tools/BashTool/prompt.ts
export const BASH_TOOL_PROMPT = `
## BashTool

Execute shell commands. Guidelines:
- Check current directory before running commands
- Use timeout for potentially long operations
- Capture both stdout and stderr
- Handle errors gracefully

Never run destructive commands without confirming.
`
3. UI Component (Optional)
TypeScript
// tools/BashTool/UI.tsx
export function BashToolUI({ input, output, status }: ToolUIProps) {
  return (
    <Box flexDirection="column">
      <Text color="blue">$ {input.command}</Text>
      {status === 'running' && <Spinner />}
      {output && (
        <Box marginLeft={2}>
          <Text>{output.content}</Text>
        </Box>
      )}
    </Box>
  )
}

Tool Categories

File System Tools
ToolPurposePermission
FileReadToolRead file contentsBackground
FileWriteToolCreate new filesDangerous
FileEditToolEdit existing filesDangerous
GlobToolFind files by patternBackground
GrepToolSearch file contentsBackground
Execution Tools
ToolPurposePermission
BashToolRun shell commandsDangerous
PowerShellToolWindows PowerShellDangerous
REPLToolInteractive REPL (ant-only)Dangerous
Code Intelligence Tools
ToolPurpose
LSPToolLanguage server operations
GrepToolText search
GlobToolFile discovery
TungstenToolInternal symbol search
Agent & Task Tools
ToolPurpose
AgentToolSpawn sub-agents
TaskCreateToolCreate background tasks
TaskStopToolKill tasks
TaskGetToolGet task output
SendMessageToolMessage between agents
Utility Tools
ToolPurpose
WebSearchToolSearch the web
WebFetchToolFetch URLs
AskUserQuestionToolPrompt user for input
NotebookEditToolEdit Jupyter notebooks
TodoWriteToolManage todo lists
ConfigToolChange settings
Workflow Tools
ToolPurpose
EnterPlanModeToolStart planning mode
ExitPlanModeToolExit planning mode
EnterWorktreeToolCreate git worktree
ExitWorktreeToolRemove git worktree

Tool Execution Flow

Plain text
┌─────────────────────────────────────────────────────────────────┐
│                    TOOL EXECUTION FLOW                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. LLM REQUESTS TOOL                                           │
│     ContentBlock: { type: 'tool_use', name: 'Bash', ... }      │
│                                                                 │
│  2. FIND TOOL                                                   │
│     findToolByName('Bash') → BashTool                           │
│                                                                 │
│  3. VALIDATE INPUT                                              │
│     tool.inputSchema.parse(input)                               │
│     └─► ZodError? Return validation error                      │
│                                                                 │
│  4. CHECK PERMISSIONS                                           │
│     permissionLevel: 'dangerous' → Show dialog                  │
│     alwaysAllowRules → Auto-approve                             │
│     alwaysDenyRules → Auto-reject                               │
│                                                                 │
│  5. PRE-HOOKS                                                   │
│     Execute pre-sampling hooks (git tracking, etc.)             │
│                                                                 │
│  6. EXECUTE                                                     │
│     tool.execute(input, context)                                │
│     ├─► Stream progress (if progress-aware)                    │
│     └─► Return ToolResult                                       │
│                                                                 │
│  7. POST-HOOKS                                                  │
│     Execute post-sampling hooks                                 │
│                                                                 │
│  8. CREATE TOOL_RESULT BLOCK                                  │
│     { type: 'tool_result', tool_use_id: '...', content: ... }  │
│                                                                 │
│  9. ADD TO MESSAGES                                             │
│     messages.push(toolResultBlock)                            │
│                                                                 │
│  10. CONTINUE QUERY                                             │
│     Send messages (with result) back to API                     │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Permission System Integration

TypeScript
// tools.ts - Tool permission levels
export const PERMISSION_LEVELS = {
  background: 0,  // Always allowed (reading files, searching)
  user: 1,       // Show UI indicator but usually allow
  dangerous: 2,  // Require explicit approval (bash, write, edit)
} as const

// Permission check flow
async function canUseTool(
  tool: Tool,
  input: unknown,
  context: ToolPermissionContext
): Promise<PermissionResult> {
  // 1. Check rules
  if (matchesAlwaysDeny(tool, input, context)) {
    return { allowed: false, reason: 'deny_rule' }
  }
  if (matchesAlwaysAllow(tool, input, context)) {
    return { allowed: true, auto: true }
  }

  // 2. Check mode
  if (context.mode === 'bypass') {
    return { allowed: true, auto: true }
  }

  // 3. Check level
  if (tool.permissionLevel === 'dangerous') {
    return await showPermissionDialog(tool, input)
  }

  return { allowed: true }
}

MCP Tool Integration

External tools via Model Context Protocol:

TypeScript
// services/mcp/client.ts
export async function connectMcpServer(config: McpServerConfig): Promise<MCPServerConnection> {
  const client = new MCPClient()
  await client.connect(config)

  // Discover tools from server
  const tools = await client.listTools()

  // Convert to internal Tool format
  const mcpTools = tools.map(t => ({
    name: `${serverName}_${t.name}`,
    description: t.description,
    inputJSONSchema: t.inputSchema,
    execute: async (input) => {
      const result = await client.callTool(t.name, input)
      return { content: result.content }
    },
    permissionLevel: 'dangerous',  // External = dangerous by default
    isMcpTool: true,
  }))

  return { client, tools: mcpTools, ... }
}

Progress Tracking

Tools can report progress:

TypeScript
export type ToolProgress = {
  type: 'progress'
  toolUseId: string
  message?: string
  percent?: number
}

// Progress-aware tool
export const LongRunningTool: Tool = {
  ...,
  isProgressAware: true,

  async *execute(input, context) {
    const { setProgress } = context

    yield { type: 'progress', message: 'Starting...', percent: 0 }

    for (let i = 0; i < steps.length; i++) {
      await doStep(steps[i])
      yield {
        type: 'progress',
        message: `Step ${i + 1}/${steps.length}`,
        percent: ((i + 1) / steps.length) * 100,
      }
    }

    return { content: 'Done!' }
  },
}

Tool UI System

Tools can render custom UI during execution:

TypeScript
// Tool.ts
export type ToolUIArgs = {
  input: unknown        // The tool input
  output?: ToolResult   // Result (if complete)
  status: 'running' | 'complete' | 'error'
  progress?: ToolProgress
}

// In tool definition
renderUI({ input, output, status, progress }) {
  return <CustomToolVisualization {...} />
}
UI Integration
TypeScript
// components/ToolUseRenderer.tsx
export function ToolUseRenderer({ toolUse }: { toolUse: ToolUseBlock }) {
  const tool = findToolByName(toolUse.name)

  // Tool provides custom UI?
  if (tool?.renderUI) {
    return tool.renderUI({
      input: toolUse.input,
      status: getToolStatus(toolUse.id),
    })
  }

  // Default UI
  return <DefaultToolUI toolUse={toolUse} />
}

Creating a New Tool

TypeScript
// 1. Create directory: tools/MyTool/

// 2. Define in MyTool.ts
import { z } from 'zod/v4'
import type { Tool, ToolUseContext, ToolResult } from '../../Tool.js'

const inputSchema = z.object({
  param: z.string(),
})

export const MyTool: Tool = {
  name: 'My',
  description: 'Does something useful',
  descriptionForAssistant: `...`,
  inputJSONSchema: { /* JSON Schema */ },
  inputSchema,
  permissionLevel: 'background',

  async execute(input, context) {
    const { param } = input as z.infer<typeof inputSchema>

    // Do work
    const result = await doSomething(param)

    return {
      type: 'tool_result',
      content: result,
    }
  },
}

// 3. Add prompt in prompt.ts
export const MY_TOOL_PROMPT = `...`

// 4. Add UI in UI.tsx (optional)
export function MyToolUI(props: ToolUIProps) {
  return <Box>...</Box>
}

// 5. Register in tools.ts
import { MyTool } from './MyTool/MyTool.js'

export function getAllBaseTools(): Tools {
  return [
    ...existingTools,
    MyTool,  // <-- Add here
  ]
}

Tool Testing

TypeScript
// MyTool.test.ts
import { MyTool } from './MyTool.js'
import { createMockToolContext } from '../../testing/toolTesting.js'

test('MyTool executes correctly', async () => {
  const context = createMockToolContext()

  const result = await MyTool.execute(
    { param: 'test' },
    context
  )

  expect(result.content).toContain('expected output')
})

test('MyTool validates input', async () => {
  await expect(
    MyTool.execute({ invalid: 'input' }, createMockToolContext())
  ).rejects.toThrow()
})

Key Concepts

1. Every Action is a Tool

Reading, writing, searching, even asking the user - all tools.

2. Schema-Driven

Zod schemas provide both type safety and runtime validation.

3. Permission Levels

Tools self-declare their danger level. System respects this.

4. Progress Streaming

Long operations can stream progress for better UX.

5. Custom UI

Complex tools can render their own UI components.

6. MCP Extensibility

External tools integrate seamlessly via MCP.


Common Tool Patterns

File-Reading Tool
TypeScript
async execute(input, context) {
  const { file_path } = input
  const content = await readFile(file_path)
  return { content }
}
Command-Executing Tool
TypeScript
async execute(input, context) {
  const { command, timeout } = input
  const result = await spawn(command, { timeout })
  return {
    content: result.output,
    is_error: result.exitCode !== 0,
  }
}
User-Interactive Tool
TypeScript
async execute(input, context) {
  const { question, options } = input
  const answer = await context.askUser(question, options)
  return { content: answer }
}

Related Documentation

  • Query System - How tools are called
  • State Management - How tools update state
  • Permissions - Detailed permission system