Permission flow: deciding whether to allow a tool call
Overview
When the model emits a tool_use, Claude Code runs it through a layered permission pipeline that combines static rules, in-prompt bash parsing, an LLM-based JIT classifier, and hook-driven rechecks before the tool actually executes .
Steps
runToolUseresolves the tool by name and, if not aborted, delegates to the streamed permission+call wrapper that ultimately invokescheckPermissionsAndCallTool.checkPermissionsAndCallToolfirst zod-validates the input, runs per-toolvalidateInput, and — for Bash — speculatively kicks off an allow-classifier in parallel with hook and dialog setup so prefix-auto-allow commands don't flash a "classifier running" indicator .- The actual policy gate is
hasPermissionsToUseTool, which calls an inner rule evaluator and then post-processes the result: anallowoutcome resets the consecutive-denial streak in auto mode, and anaskoutcome gets routed into mode-specific transforms . - In
dontAskmode anaskbecomes a harddeny; inauto(or plan-mode with auto active) the decision is diverted to the YOLO/JIT classifier path instead of prompting the user . - Before calling the classifier, fast-paths short-circuit: non-classifier-approvable safety checks stay immune, PowerShell without the
POWERSHELL_AUTO_MODEflag requires interactive approval, anacceptEdits-mode re-check can auto-allow safe file edits, and tools on the safe allowlist skip the classifier entirely . - For Bash specifically,
bashToolHasPermissionruns an AST parse (tree-sitter, gated byCLAUDE_CODE_DISABLE_COMMAND_INJECTION_CHECKand a GrowthBook killswitch) and matches exact/prefix/deny rules; a "too-complex" or semantically suspicious parse degrades toaskand attaches apendingClassifierCheckwhenBASH_CLASSIFIERis on . - The JIT classifier entrypoint
classifyYoloActionbuilds a compact transcript viabuildTranscriptEntriesandtoCompactBlock, prepends a CLAUDE.md message frombuildClaudeMdMessage, and assembles the system prompt throughbuildYoloSystemPromptwhich injects userautoMode.allow/soft_denyrules fromgetAutoModeConfig. - A cache breakpoint is placed on the action block using
getCacheControlso that stage-2 of the two-stage classifier reuses the same cached prefix as stage-1 . - If two-stage mode is enabled via env or GrowthBook it dispatches to
classifyYoloActionXml, otherwise it callssideQuerywith the classifier model fromgetClassifierModel, logs outcome vialogAutoModeOutcome, and dumps request/response whenCLAUDE_CODE_DUMP_AUTO_MODEis set . - While the dialog is pending, hook and bridge paths can call
recheckPermission, which re-runshasPermissionsToUseTooland, if the fresh result is nowallow, atomically claims the decision and resolves the waiting prompt without user action . - The printed-SDK
canUseToolwraps all of this: if the main result is ask, it races thepermissionPromptTool.callagainst the abort signal so Ctrl+C can interrupt a blocked prompt, then maps the tool's JSON output back into aPermissionDecision. - For sub-agent handoffs,
classifyHandoffIfNeededfeeds the sub-agent transcript back throughclassifyYoloActionand injects a security-warning string into the parent's result when the classifier blocks .
State touched
- The classifier caches its last request batch for debugging via .
- The system-prompt builder reads cached CLAUDE.md content via .
Decisions
No design decisions were provided in the whitelist for this flow.