Claude Code 学习站

Agent SDK 权限控制:模式、规则与评估流程

整理 Claude Agent SDK 权限系统官方文档:六步评估流程、allow/deny 规则语法、六种权限模式及各模式的自动批准范围。

本页目录7
AI 摘要 · 已核查整理于 2026-07-28原文:Configure permissions(Anthropic)Agent SDK权限控制Claude Code工具调用
要点速览
  • 权限判定按固定顺序执行:Hooks → deny 规则 → ask 规则 → 权限模式 → allow 规则 → canUseTool 回调,任一步命中即终止后续判定
  • disallowed_tools 命名整个工具(如 Bash)会让 Claude 完全看不到该工具;而 disallowed_tools=["Bash(rm *)"] 只拦截匹配的调用,在任何模式(包括 bypassPermissions)下都生效
  • allowed_tools 不会限制 bypassPermissions 模式——该模式下未被 allow 规则匹配的工具仍会通过权限模式这一步被批准,若要限制需改用 disallowed_tools
  • auto、AskUserQuestion、要求用户交互的 MCP 工具、组织设为 ask 的连接器工具,以及针对『关键路径』的 rm/rmdir 删除,即使命中 allow 规则也仍会走 canUseTool 回调(dontAsk 模式下则直接拒绝)
  • acceptEdits 模式自动批准文件编辑及 mkdir/touch/rm/rmdir/mv/cp/sed 等文件系统命令,但仅限工作目录或 additionalDirectories 内的路径
  • plan 模式下文件编辑与(v2.1.212+)修改文件的 shell 命令永远不会被 allow 规则自动批准,始终会走 canUseTool 回调

本文是对 Claude Agent SDK 官方文档「Configure permissions」页的中文整理,完整与最新内容以原文为准:https://code.claude.com/docs/en/agent-sdk/permissions

Claude Agent SDK 提供权限控制机制来管理 Claude 如何使用工具。使用权限模式(permission modes)和规则(rules)来定义哪些操作可自动放行,其余情况则交给 canUseTool 回调 在运行时处理。

权限的评估顺序

当 Claude 请求调用某个工具时,SDK 按以下顺序检查权限:

  1. Hooks(钩子) 先运行 hooks。钩子可以直接拒绝调用,也可以放行让流程继续。钩子返回 allow 并不会跳过下面的 deny 和 ask 规则——这些规则无论如何都会被评估。PreToolUse 钩子的 allow 也无法批准针对关键路径(critical path)rmrmdir 删除操作。

  2. Deny 规则 检查 deny 规则(来自 disallowed_tools 以及 settings.json)。若命中 deny 规则,工具调用会被拦截,即使处于 bypassPermissions 模式下也一样。像 Bash 这种裸工具名的 deny 规则会在此步骤评估之前,直接把该工具定义从 Claude 的上下文中移除;只有像 Bash(rm *) 这样带作用域的规则才会在这一步被检查。

  3. Ask 规则 检查来自 settings.jsonask 规则。若命中 ask 规则,调用会流转到你的 canUseTool 回调 请求确认,即使在 bypassPermissions 模式下也是如此。

需要用户交互的工具行为相同:AskUserQuestion 以及服务端设置了 _meta[\"anthropic/requiresUserInteraction\"] 的 MCP 工具,总是会流转到回调,即使 allow 规则命中也一样。在 dontAsk 模式下,这两种情况会被直接拒绝,因为该模式从不弹出提示。该 MCP 注解需要 Claude Code v2.1.199 或更高版本。

claude.ai 连接器中被组织设为 ask 的工具也会在这一步流出。所有调用都会流转到回调,即使在 bypassPermissions 模式下、即使命中了 allow 规则也一样。回调收到的原因是「Your organization requires approval for this tool」。在 dontAsk 模式下则直接拒绝。

  1. 权限模式(Permission mode) 应用当前生效的权限模式bypassPermissions 会批准所有到达这一步的调用,但针对关键路径rmrmdir 删除除外,这类调用会继续流转。acceptEdits 会批准「接受编辑模式」章节列出的文件操作。plan 模式会把文件编辑和 shell 写入类工具一律路由到你的 canUseTool 回调,无论 allow 规则是否命中,以确保规划阶段不会自动批准写操作。其余模式则继续向下流转。

  2. Allow 规则 检查 allow 规则(来自 allowed_tools 以及 settings.json)。若规则命中,工具即被批准。针对关键路径rmrmdir 删除永远不会被 allow 规则批准:在会弹出提示的模式下会到达你的回调;在 auto 模式下(Claude Code v2.1.218 及以上)会交给分类器;在 dontAsk 模式下会被拒绝。

  3. canUseTool 回调 若以上步骤都未能解决,则调用你的 canUseTool 回调 做出决策。在 dontAsk 模式下,此步骤会被跳过,工具调用直接被拒绝。

如果你传入了 canUseTool 回调,但 TypeScript SDK 在某些配置下会在回调被咨询之前就自动批准调用,SDK 会在创建 query 时发出一次 Node.js 进程警告(process.on('warning', ...)),警告 code 为 CLAUDE_SDK_CAN_USE_TOOL_SHADOWED。会触发该警告的两种配置:

带具体作用域(specifier)的条目如 Bash(ls *),以及 acceptEdits 模式,不会触发该警告;来自 settings 文件的 allow 规则对该检查也不可见。

process.on('warning', ...) 监听并匹配该 code 来记录或抑制它。若想让每一次工具调用都无条件经过一道关口(不论模式与规则如何),请改用 PreToolUse hook

本文主要讲解 allow/deny 规则权限模式。其余两个步骤见:

Allow 与 Deny 规则

allowed_toolsdisallowed_tools(TypeScript 中为 allowedTools / disallowedTools)会向上述评估流程中的 allow / deny 规则列表追加条目。若你在 allowed_tools 中列出了某个任务跟踪工具,Claude Code 也会为该会话开启对应功能。任何未列在 allowed_tools 中的其他工具依然可用,并会继续流转到权限模式这一步。Deny 规则的行为取决于它命名的是整个工具,还是在某个工具内部限定了一个匹配模式(pattern)。

OptionEffect
allowed_tools=[\"Read\", \"Grep\"]ReadGrep 被自动批准。未列出的其他工具仍然存在,会继续流转到权限模式和 canUseTool
disallowed_tools=[\"Bash\"]Bash 工具定义会从请求中被移除。Claude 看不到该工具,也无法尝试调用它。
disallowed_tools=[\"Bash(rm *)\"]Bash 仍然可用。匹配 rm * 的调用在任何权限模式下(包括 bypassPermissions)都会被拒绝。其他 Bash 调用会继续流转到权限模式。
disallowed_tools=[\"*\"]所有工具定义都会从请求中被移除。Deny 规则支持工具名通配符:\"*\" 匹配所有工具,\"mcp__*\" 匹配所有服务器下的所有 MCP 工具。

Allow 规则只在字面量 mcp__<server>__ 前缀之后才支持工具名通配符。server 段必须不含通配符,以确保规则指向你实际配置的某个具体服务器:mcp__puppeteer__* 匹配 puppeteer 服务器下的所有工具,mcp__github__get_* 匹配它以 get_ 开头的工具。而未锚定的写法如 allowed_tools=[\"*\"]allowed_tools=[\"mcp__*\"] 会被忽略,并在启动时给出警告,不会自动批准任何东西。

ReadEdit 的作用域规则接受一个路径匹配模式(path pattern)。Edit(path) 规则会约束所有会写文件的内置工具,包括 WriteNotebookEdit;而 Write(path) 规则永远不会被文件权限检查所匹配到。

绝对文件系统路径请用 //path:deny 规则 Edit(//secrets/**) 会拦截磁盘上 /secrets 目录下任意位置的写入。若只用单个前导斜杠,Edit(/secrets/**) 则会以规则的来源为锚点——对于通过 allowed_toolsdisallowed_tools 传入的规则,锚点就是会话的工作目录,因此该规则不会拦截磁盘上真正的 /secrets。四种锚定形式及 settings 文件中规则的解析方式,详见 Read and Edit rules

警告:自动批准的工具永远不会到达 canUseTool 在更早的步骤中被批准的工具调用——无论是被 acceptEditsbypassPermissions 批准,还是被 allow 规则批准——都会跳过你的 canUseTool 回调,因此你放在回调里的权限检查会被静默绕过。AskUserQuestion、标记了 _meta[\"anthropic/requiresUserInteraction\"] 的 MCP 工具、被组织设为 ask 的连接器工具,以及针对关键路径rm/rmdir 删除,即使 allow 规则命中,仍会到达回调。在 auto 模式下,针对关键路径的删除会走分类器而非回调,上面列出的其他情况仍会到达回调(该分类器路由要求 Claude Code v2.1.218 及以上)。在 dontAsk 模式下,这些调用会被直接拒绝,不会调用回调。

覆盖范围取决于条目的写法:像 Readmcp__github__get_issue 这样的裸名称,会自动批准对该工具的每一次调用(上述例外情况除外);而像 Bash(ls *) 这样带作用域的规则,只会自动批准匹配的调用,其他 Bash 调用仍会流转到回调。若需要在每一次工具调用上都强制执行检查,请使用 PreToolUse hook:hooks 会在其他所有步骤之前运行,且钩子的拒绝即使在 bypassPermissions 模式下也依然生效。

若要打造一个「锁死」的 agent,可将 allowedToolspermissionMode: \"dontAsk\" 搭配使用。列出的工具会被批准(上文警告中提到的「总是提示」的工具除外);其余一律直接拒绝而不弹出提示:

const options = {
  allowedTools: ["Read", "Glob", "Grep"],
  permissionMode: "dontAsk"
};

警告:allowed_tools 不会约束 bypassPermissions allowed_tools 只是预先批准你列出的工具。未列出的其他工具不会被任何 allow 规则匹配到,会继续流转到权限模式这一步,而 bypassPermissions 会批准它们。也就是说,同时设置 allowed_tools=[\"Read\"]permission_mode=\"bypassPermissions\",依然会批准所有工具,包括 BashWriteEdit。如果你需要 bypassPermissions 的同时又想拦截特定工具,请使用 disallowed_tools

你也可以在 .claude/settings.json 中声明式地配置 allow、deny、ask 规则。这些规则会在启用了 project 这个 setting source 时被读取——而使用默认的 query() 选项时,project 默认就是启用的。如果你显式设置了 setting_sources(TypeScript 中为 settingSources),需要包含 \"project\" 才能让这些规则生效。规则语法详见 Permission settings

权限模式(Permission modes)

权限模式对 Claude 如何使用工具提供全局控制。你可以在调用 query() 时设置权限模式,也可以在流式会话过程中动态更改。

可用模式

SDK 支持以下权限模式:

ModeDescriptionTool behavior
default标准权限行为没有自动批准;未匹配的工具触发你的 canUseTool 回调
dontAsk拒绝而非提示任何未被 allowed_tools 或规则预先批准的调用都会被拒绝;被组织设为 ask 的连接器工具,以及需要用户交互的工具,即使你已预先批准,也会被拒绝,针对关键路径rm/rmdir 删除同样如此。canUseTool 永远不会被调用
acceptEdits自动接受文件编辑文件编辑及文件系统操作mkdirrmmv 等)会被自动批准
bypassPermissions绕过权限检查工具运行时不会弹出权限提示,没有任何模式会自动批准的操作除外。请谨慎使用
plan规划模式Claude 探索并制定计划,但不会编辑你的源文件;文件编辑永远不会被自动批准,会通过 canUseTool 回调提示
auto模型分类批准由一个模型分类器来批准或拒绝权限提示。可用性见 Auto mode

警告:子代理(Subagent)的继承规则。 子代理会继承父会话的权限模式。AgentDefinitionpermissionMode 可以覆盖它,但当父会话使用 bypassPermissionsacceptEditsauto 时例外:这三种模式会应用到每一个子代理,无法按子代理单独覆盖。当 bypass 模式被 permissions.disableBypassPermissionsMode 禁用时,Claude Code 也会忽略某个 definition 中的 permissionMode: \"bypassPermissions\",该子代理会转而使用父会话的模式运行。

子代理可能拥有与主 agent 不同的系统提示词,行为约束也可能更弱,因此继承 bypassPermissions 会赋予它们完整、自主的系统访问权限。没有任何模式会自动批准的操作在子代理上依然适用。

设置权限模式

你可以在启动 query 时一次性设置权限模式,也可以在会话进行中动态更改。

方式一:在创建 query 时设置

传入 permission_mode(Python)或 permissionMode(TypeScript)来创建 query。除非动态更改,该模式会在整个会话期间生效。

import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions


async def main():
    async for message in query(
        prompt="Help me refactor this code",
        options=ClaudeAgentOptions(
            permission_mode="default",  # Set the mode here
        ),
    ):
        if hasattr(message, "result"):
            print(message.result)


asyncio.run(main())
import { query } from "@anthropic-ai/claude-agent-sdk";

async function main() {
  for await (const message of query({
    prompt: "Help me refactor this code",
    options: {
      permissionMode: "default" // Set the mode here
    }
  })) {
    if ("result" in message) {
      console.log(message.result);
    }
  }
}

main();

方式二:在流式会话过程中动态更改

调用 set_permission_mode()(Python)或 setPermissionMode()(TypeScript)可在会话中途更改模式。新模式会立即对之后的所有工具请求生效。这适用于「先严格后放宽」的场景,例如在你审核过 Claude 最初的方案后,再切换到 acceptEdits

import asyncio
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions


async def main():
    async with ClaudeSDKClient(
        options=ClaudeAgentOptions(
            permission_mode="default",  # Start in default mode
        )
    ) as client:
        await client.query("Help me refactor this code")

        # Change mode dynamically mid-session
        await client.set_permission_mode("acceptEdits")

        # Process messages with the new permission mode
        async for message in client.receive_response():
            if hasattr(message, "result"):
                print(message.result)


asyncio.run(main())
import { query } from "@anthropic-ai/claude-agent-sdk";

async function main() {
  const q = query({
    prompt: "Help me refactor this code",
    options: {
      permissionMode: "default" // Start in default mode
    }
  });

  // Change mode dynamically mid-session
  await q.setPermissionMode("acceptEdits");

  // Process messages with the new permission mode
  for await (const message of q) {
    if ("result" in message) {
      console.log(message.result);
    }
  }
}

main();

各模式详情

Accept edits 模式(acceptEdits

自动批准文件操作,使 Claude 无需提示即可编辑代码。其他工具(如非文件系统操作的 Bash 命令)仍需正常的权限流程。

会被自动批准的操作:

  • 文件编辑(EditWrite 工具)
  • 文件系统命令:mkdirtouchrmrmdirmvcpsed

以上两类都只适用于工作目录或 additionalDirectories 内的路径。工作目录之外的路径、对受保护路径的写入,以及针对关键路径rm/rmdir 删除,仍然会弹出提示。

适用场景: 你信任 Claude 的编辑结果,想要更快的迭代速度,例如在原型开发或在隔离目录中工作时。

Don't ask 模式(dontAsk

将任何权限提示都转换为拒绝。被 allowed_toolssettings.json 的 allow 规则或某个 hook 预先批准的工具照常运行。被组织设为 ask 的连接器工具、需要用户交互的工具,以及针对关键路径rm/rmdir 删除,即使 allow 规则命中,也一律拒绝。PreToolUse hook 的 allow 同样无法解除对关键路径删除的拒绝。除此之外的一切都会被拒绝,且不会调用 canUseTool

适用场景: 你希望为无人值守(headless)的 agent 设定一个固定、明确的工具可用范围,并且更倾向于硬性拒绝,而不是在 canUseTool 缺失时静默依赖它。

Bypass permissions 模式(bypassPermissions

自动批准工具使用,不弹出提示,下方警告中列出的情况除外。Hooks 依然会执行,并可在需要时阻止操作。

警告: 请极其谨慎地使用此模式。在该模式下 Claude 拥有完整的系统访问权限。仅在你信任所有可能操作的受控环境中使用。

allowed_tools 不会约束此模式——所有工具都会被批准,而不仅仅是你列出的那些。以下控制机制依然生效:

  • Deny 规则、显式的 ask 规则以及 hooks,会在模式检查之前被评估,仍可拦截某个工具。
  • 被组织设为 ask 的连接器工具、需要用户交互的工具,以及针对关键路径rm/rmdir 删除,仍会流转到你的 canUseTool 回调。
  • 跨会话消息传递的防护机制依然适用。

Plan 模式(plan

Claude 会探索代码库并产出一份计划,但不会编辑你的源文件。只读工具的行为与 default 权限模式下相同。

Plan 模式下文件编辑永远不会被自动批准,即使 allow 规则命中也是如此,而是会通过你的 canUseTool 回调提示。在 Claude Code v2.1.212 及以上版本,会修改文件的 shell 命令(如 touchrm)也会以同样的方式到达你的 canUseTool 回调。

Claude 在最终确定计划之前,可能会用 AskUserQuestion 来澄清需求。关于如何处理这些提示,见 处理批准与用户输入

适用场景: 你希望 Claude 只提出变更方案而不实际执行,例如在代码评审阶段,或需要在变更真正生效前先行审批。

相关资源

关于权限评估流程中的其他步骤: