How does the permission system decide whether to allow a tool call, including in-prompt decisions, JIT classifier, hook injection, and the permission cache

en
93.8% sentence pass·15/16 cited·15/15 citations valid·95 fn·0 dec·769 sem
Permission & Security FrameworkPermissions UITool FrameworkSettings & ConfigurationContext & Prompt System

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

  1. runToolUse resolves the tool by name and, if not aborted, delegates to the streamed permission+call wrapper that ultimately invokes checkPermissionsAndCallTool .
  2. checkPermissionsAndCallTool first zod-validates the input, runs per-tool validateInput, 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 .
  3. The actual policy gate is hasPermissionsToUseTool, which calls an inner rule evaluator and then post-processes the result: an allow outcome resets the consecutive-denial streak in auto mode, and an ask outcome gets routed into mode-specific transforms .
  4. In dontAsk mode an ask becomes a hard deny; in auto (or plan-mode with auto active) the decision is diverted to the YOLO/JIT classifier path instead of prompting the user .
  5. Before calling the classifier, fast-paths short-circuit: non-classifier-approvable safety checks stay immune, PowerShell without the POWERSHELL_AUTO_MODE flag requires interactive approval, an acceptEdits-mode re-check can auto-allow safe file edits, and tools on the safe allowlist skip the classifier entirely .
  6. For Bash specifically, bashToolHasPermission runs an AST parse (tree-sitter, gated by CLAUDE_CODE_DISABLE_COMMAND_INJECTION_CHECK and a GrowthBook killswitch) and matches exact/prefix/deny rules; a "too-complex" or semantically suspicious parse degrades to ask and attaches a pendingClassifierCheck when BASH_CLASSIFIER is on .
  7. The JIT classifier entrypoint classifyYoloAction builds a compact transcript via buildTranscriptEntries and toCompactBlock, prepends a CLAUDE.md message from buildClaudeMdMessage, and assembles the system prompt through buildYoloSystemPrompt which injects user autoMode.allow/soft_deny rules from getAutoModeConfig .
  8. A cache breakpoint is placed on the action block using getCacheControl so that stage-2 of the two-stage classifier reuses the same cached prefix as stage-1 .
  9. If two-stage mode is enabled via env or GrowthBook it dispatches to classifyYoloActionXml, otherwise it calls sideQuery with the classifier model from getClassifierModel, logs outcome via logAutoModeOutcome, and dumps request/response when CLAUDE_CODE_DUMP_AUTO_MODE is set .
  10. While the dialog is pending, hook and bridge paths can call recheckPermission, which re-runs hasPermissionsToUseTool and, if the fresh result is now allow, atomically claims the decision and resolves the waiting prompt without user action .
  11. The printed-SDK canUseTool wraps all of this: if the main result is ask, it races the permissionPromptTool.call against the abort signal so Ctrl+C can interrupt a blocked prompt, then maps the tool's JSON output back into a PermissionDecision .
  12. For sub-agent handoffs, classifyHandoffIfNeeded feeds the sub-agent transcript back through classifyYoloAction and 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.