Tools and permissions

The tool system has three layers: a registry that builds the available tool pool, orchestration that decides safe execution order, and execution that validates input, runs hooks, asks for permission, calls the tool, and turns results back into model messages.

Execution flow

assembleToolPool()
  built-in tools + MCP tools
  deny filters
  stable sort for prompt cache
  dedupe by name

streaming or regular executor
  find tool by name
  validate input with zod schema
  run PreToolUse hooks
  ask permission when needed
  tool.call(input, context)
  map result to tool_result user message
  return contextModifier if needed
The Tool type is the common interface

A tool includes a prompt-visible name and description, input schemas, execution metadata, permission behavior, concurrency/read-only/destructive/open-world hints, MCP metadata when applicable, and a call method. ToolUseContext passes abort state, app state accessors, permission callbacks, UI callbacks, read-file state, and MCP resources into tool calls.

External reference: Zod, used for schema validation concepts.

Tool pool assembly merges built-ins and MCP

getAllBaseTools defines the core local tools. getTools filters by mode, deny rules, REPL availability, and tool enablement. assembleToolPool then combines built-ins and MCP tools, applies deny filters, sorts partitions for prompt-cache stability, and deduplicates by name.

Orchestration separates concurrent and serial work

runTools partitions tool uses into concurrency-safe and serial groups. Safe tools can run together under a concurrency limit, while unsafe tools run exclusively. The streaming executor performs a similar check while the model is still streaming, so safe tool work can begin before the whole assistant message is complete.

runToolUse is validation plus policy plus call

runToolUse resolves the tool name, handles unknown tools, validates input with the tool schema, runs speculative classifiers and pre-tool hooks, asks the permission layer, produces denied tool_result messages when needed, executes tool.call when allowed, and maps the result into a user tool_result message.

Permission requests are model policy plus interactive UI

useCanUseTool handles deny and ask cases, coordinator and worker behavior, speculative bash classification, and interactive permission handling. The permission context can log decisions, persist them, abort, cancel, and let permission request hooks allow or deny. The interactive handler pushes a ToolUseConfirm item to app state, which the permissions UI renders.

External reference: Anthropic tool use.