Built-in tools and permissions
This page identifies the built-in tool surface and the root permission/filtering flags visible in the extracted cli.js.
Use Tool inventory and schemas for the canonical tool-family inventory and schema-owner table. This page owns the built-in permission and ToolExecutionBoundary explanation.
Source anchors
| Semantic alias | Source | Approximate location | String or symbol | Meaning |
|---|---|---|---|---|
| BashToolName | cli.js | line ~446, byte 0x309242 | var Rq="Bash" | Shell-command tool name. |
| ReadToolName | cli.js | line ~481, byte 0x30a2ba | var Bq="Read" | File-read tool name. |
| EditToolName | cli.js | line ~549, byte 0x31b727 | var v7="Edit" | File-edit tool name. |
| WriteToolName | cli.js | line ~941, byte 0x4686f7 | var $9="Write" | File-write tool name. |
| GlobToolName | cli.js | line ~482, byte 0x30a7e0 | var B1="Glob" | File-pattern search tool name. |
| GrepToolName | cli.js | line ~461, byte 0x3097ed | var V9="Grep" | Content-search tool name. |
| WebFetchToolName | cli.js | line ~770, byte 0x436b69 | var gD="WebFetch" | URL fetch tool name. |
| WebSearchToolName | cli.js | line ~1091, byte 0x480490 | var RI="WebSearch" | Web search tool name. |
| TodoWriteToolName | cli.js | line ~1091, byte 0x4804bf | var HV="TodoWrite" | Todo list tool name. |
| SkillToolName | cli.js | line ~1091, byte 0x4804d2 | var XX="Skill" | Skill-loading tool name. |
| ToolVisibilityFlag | cli.js | line ~19525, byte 0xdc0a43 | --tools <tools...> | Selects available tools from the built-in set. |
| ToolAllowRuleFlag | cli.js | line ~19525, byte 0xdc09bd | --allowedTools, --allowed-tools <tools...> | Allows matching tool calls. |
| ToolDenyRuleFlag | cli.js | line ~19525, byte 0xdc0b05 | --disallowedTools, --disallowed-tools <tools...> | Denies matching tool calls. |
| PermissionModeFlag | cli.js | line ~19525, byte 0xdc10d9 | --permission-mode <mode> | Selects permission policy mode. |
Built-in tool families
| Family | Tool names | Observed role |
|---|---|---|
| Shell/process | Bash, BashOutput, task/agent output aliases | Runs shell commands and surfaces command output/status. |
| File read/search | Read, Glob, Grep | Reads files, expands patterns, and searches content. |
| File write/edit | Edit, Write, MultiEdit, NotebookEdit | Modifies files/notebooks and participates in code-edit permission telemetry. |
| Web | WebFetch, WebSearch | Fetches URLs/domains or performs web search with validation. |
| Planning/todos | TodoWrite, ExitPlanMode | Tracks task plan state and exits plan mode. |
| Skills/agents | Skill, TaskCreate, TaskGet, TaskList, TaskUpdate, SendMessage | Loads skills and dispatches/observes task or agent work. |
Permission and filtering flow
flowchart TD RootFlags[--tools / --allowedTools / --disallowedTools] --> Visible[Model-visible tool set] Settings[settings and managed policy] --> Visible Visible --> ToolCall[Tool call] ToolCall --> Mode[--permission-mode] Mode --> Deny[Deny rules] Deny -->|match| Block[Denied] Deny -->|no match| Allow[Allow rules / auto mode / prompt] Allow --> Execute[Execute tool] Execute --> Events[events, telemetry, transcript]Root permission surfaces
| Surface | Meaning |
|---|---|
--tools <tools...> | Restricts the set of built-in tools made available. Empty string disables all; default restores default set. |
--allowedTools / --allowed-tools | Adds allow rules such as Bash(git *) or explicit tool names. |
--disallowedTools / --disallowed-tools | Adds deny rules; deny-style surfaces are also referenced by prompt text warning against bypass. |
--permission-mode <mode> | Sets session permission behavior, including modes such as acceptEdits, auto, and bypass-style modes in internal mappings. |
--permission-prompt-tool <tool> | Routes permission prompts through an MCP tool in print mode. |
--dangerously-skip-permissions | Bypass-style flag with explicit safety-sensitive naming; docs should avoid treating it as normal mode. |
High-signal validation strings
The bundle contains validation for web permissions:
WebSearch does not support wildcardsWebFetch permissions use domain format, not URLs- examples such as
WebFetch(domain:example.com)
These strings confirm that URL/domain permission syntax is parsed separately from generic tool names.
Permission and execution internals
This section deepens the visible surfaces above by following the approval/execution boundary around built-in and MCP tools. The key observation is that tool execution is not a direct tool_call → run edge. It is mediated by tool visibility, permission modes, rule/classifier decisions, PreToolUse hooks, SDK can_use_tool control requests, denial events, optional retry hooks, execution telemetry, and read-before-write guards.
Additional anchors
| Semantic alias | Source | Approximate location | String or symbol | Meaning |
|---|---|---|---|---|
| PreToolUsePermissionHook | cli.js | line ~3553, byte 0x876552 | hookPermissionResult, PreToolUse | PreToolUse hook can allow, ask, deny, defer, or update input. |
| ToolExecutionBoundary | cli.js | line ~4202, byte 0x8a813a | function U85 | Tool execution boundary containing allow/deny telemetry. |
| ToolDeniedTelemetry | cli.js | line ~4202, byte 0x8a9617 | tengu_tool_use_can_use_tool_rejected | Denied tool-use telemetry path. |
| ToolAllowedTelemetry | cli.js | line ~4202, byte 0x8a9a89 | tengu_tool_use_can_use_tool_allowed | Allowed tool-use telemetry path. |
| PermissionDeniedRetryHint | cli.js | line ~4202, byte 0x8a9a2d | The PermissionDenied hook indicated you may retry this tool call. | Denial hook can request retry feedback. |
| CanUseToolDenialFrame | cli.js | line ~9564, byte 0xcc4a2a | createCanUseTool, permission_denied | SDK/bridge can-use-tool wrapper emits denial system frame. |
| CanUseToolControlRequest | cli.js | line ~9564, byte 0xcc4dab | sendControlRequest({subtype:"can_use_tool"...}) | Ask path surfaces as a host/SDK control request. |
| PermissionPromptToolFlag | cli.js | line ~19356, byte 0xdb0bc6 | --permission-prompt-tool | Permission prompts can be routed through an MCP tool. |
| ReadBeforeWriteGuard | cli.js | line ~3226, byte 0x821507 | File has not been read yet. Read it first before writing to it. | Edit guard requires a prior read state. |
Permission pipeline
flowchart TD Visible[Visible tool set] --> Call[Model tool call] Call --> PreHook[PreToolUse hooks] PreHook --> Decision[Permission decision] Decision -->|allow| AllowedTelemetry[tengu_tool_use_can_use_tool_allowed] Decision -->|deny| DeniedTelemetry[tengu_tool_use_can_use_tool_rejected] Decision -->|ask| SDKAsk[can_use_tool control_request] SDKAsk --> HostResponse[permission_response / control_response] HostResponse --> Decision DeniedTelemetry --> PermissionDeniedHook[PermissionDenied hook] PermissionDeniedHook --> RetryHint[optional retry hint] AllowedTelemetry --> Guards[tool-specific guards] Guards --> Execute[execute tool]PreToolUse is part of authorization, not only notification
The PreToolUse hook path yields structured hookPermissionResult values whose behavior can:
allowa tool;askfor permission;denythe tool;defera decision;- provide
updatedInput; - add
additionalContext.
Hooks therefore participate before execution and can mutate the candidate tool input — they are not merely after-the-fact logs.
Execution boundary in ToolExecutionBoundary
ToolExecutionBoundary is the source-confirmed boundary for a tool-use decision. It contains both telemetry branches (tengu_tool_use_can_use_tool_rejected and _allowed). On rejection, the function builds tool-result-style denial messages. If a PermissionDenied hook returns retry information, the runtime can add a model-visible meta message:
The PermissionDenied hook indicated you may retry this tool call.
On allow, it can use updatedInput from the permission decision before continuing toward execution.
SDK and Remote Control ask path
The bridge/app class around createCanUseTool wraps the same decision model for SDK or remote hosts:
- Calls the underlying permission resolver.
- If the decision is
allow, returns immediately. - If the decision is
deny, enqueues a system frame with subtypepermission_denied, includingtool_name,tool_use_id, optionalagent_id,decision_reason_type,decision_reason, and the model-facing message. - Otherwise sends a control request with subtype
can_use_tooland waits for a host response.
This is why the headless schema has both permission_denied system events and can_use_tool control requests: auto-deny/deny short-circuits and ask-style host prompts are different paths.
MCP permission-prompt tool
--permission-prompt-tool adds another approval route. The helper around line ~19356 validates that the named tool exists and is an MCP tool with an inputJSONSchema; if missing or not a valid MCP tool, it writes an error and exits. Permission prompting can therefore be delegated to MCP, but only through schema-bearing MCP tools.
Tool-specific guard examples
| Guard | Anchor | Mechanism |
|---|---|---|
| Read-before-edit | File has not been read yet. Read it first before writing to it. | Edit/write/notebook paths check readFileState before mutating files. |
| Modified-after-read | File content has changed since it was last read. | Edit path compares timestamps/content and asks the model to refresh with Read. |
| WebSearch syntax | WebSearch does not support wildcards | Permission pattern validation rejects wildcard search terms. |
| WebFetch syntax | WebFetch permissions use domain format, not URLs | URL permissions use domain:<host> rather than raw URLs. |
| Code-edit telemetry | claude_code.code_edit_tool.decision | Edit/Write/NotebookEdit permission decisions are counted separately. |
Implementation takeaways
- The model-visible tool set is only the first gate; execution still goes through hooks, permission decisions, SDK/host prompts, and tool-specific guards.
PreToolUsecan affect authorization and input, whilePermissionDeniedcan feed a retry hint back to the model.- SDK/Remote Control hosts see a structured
can_use_toolcontrol request only for ask-style decisions; denial shortcuts becomepermission_deniedframes. - File-edit tools enforce a read-before-write invariant, which explains why the model often must call
ReadbeforeEdit/Write/NotebookEdit.
Sandbox handoff
Tool permission answers the question “may this tool run?”; the command sandbox answers “what can the approved process access once it runs?” The Bash/PowerShell tool schemas include dangerouslyDisableSandbox, but the runtime treats that as a sandboxOverride permission reason rather than a silent bypass. For the platform-specific Linux/macOS sandbox wrapper, network/filesystem policy, $TMPDIR guidance, and strict-vs-fallback modes, see Sandbox and isolation.
Related docs
Created and maintained by Yingting Huang.