本页目录7
- 权限判定按固定顺序执行: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 按以下顺序检查权限:
-
Hooks(钩子) 先运行 hooks。钩子可以直接拒绝调用,也可以放行让流程继续。钩子返回
allow并不会跳过下面的 deny 和 ask 规则——这些规则无论如何都会被评估。PreToolUse钩子的 allow 也无法批准针对关键路径(critical path)的rm或rmdir删除操作。 -
Deny 规则 检查
deny规则(来自disallowed_tools以及 settings.json)。若命中 deny 规则,工具调用会被拦截,即使处于bypassPermissions模式下也一样。像Bash这种裸工具名的 deny 规则会在此步骤评估之前,直接把该工具定义从 Claude 的上下文中移除;只有像Bash(rm *)这样带作用域的规则才会在这一步被检查。 -
Ask 规则 检查来自 settings.json 的
ask规则。若命中 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 模式下则直接拒绝。
-
权限模式(Permission mode) 应用当前生效的权限模式。
bypassPermissions会批准所有到达这一步的调用,但针对关键路径的rm和rmdir删除除外,这类调用会继续流转。acceptEdits会批准「接受编辑模式」章节列出的文件操作。plan模式会把文件编辑和 shell 写入类工具一律路由到你的canUseTool回调,无论 allow 规则是否命中,以确保规划阶段不会自动批准写操作。其余模式则继续向下流转。 -
Allow 规则 检查
allow规则(来自allowed_tools以及 settings.json)。若规则命中,工具即被批准。针对关键路径的rm和rmdir删除永远不会被 allow 规则批准:在会弹出提示的模式下会到达你的回调;在auto模式下(Claude Code v2.1.218 及以上)会交给分类器;在dontAsk模式下会被拒绝。 -
canUseTool回调 若以上步骤都未能解决,则调用你的canUseTool回调 做出决策。在dontAsk模式下,此步骤会被跳过,工具调用直接被拒绝。
如果你传入了 canUseTool 回调,但 TypeScript SDK 在某些配置下会在回调被咨询之前就自动批准调用,SDK 会在创建 query 时发出一次 Node.js 进程警告(process.on('warning', ...)),警告 code 为 CLAUDE_SDK_CAN_USE_TOOL_SHADOWED。会触发该警告的两种配置:
permissionMode: 'bypassPermissions'——除了没有任何模式会自动批准的操作外,批准所有到达该步骤的调用。- 每一条裸的
allowedTools条目,例如\"Read\",会在咨询回调之前批准该整个工具(同样,没有任何模式会自动批准的操作除外)。
带具体作用域(specifier)的条目如 Bash(ls *),以及 acceptEdits 模式,不会触发该警告;来自 settings 文件的 allow 规则对该检查也不可见。
用 process.on('warning', ...) 监听并匹配该 code 来记录或抑制它。若想让每一次工具调用都无条件经过一道关口(不论模式与规则如何),请改用 PreToolUse hook。
本文主要讲解 allow/deny 规则与权限模式。其余两个步骤见:
- Hooks:运行自定义代码来放行、拒绝或修改工具请求,见 用 hooks 控制执行。
- canUseTool 回调:当前面所有步骤都无法解决时,在运行时向用户请求批准,见 处理批准与用户输入。
Allow 与 Deny 规则
allowed_tools 与 disallowed_tools(TypeScript 中为 allowedTools / disallowedTools)会向上述评估流程中的 allow / deny 规则列表追加条目。若你在 allowed_tools 中列出了某个任务跟踪工具,Claude Code 也会为该会话开启对应功能。任何未列在 allowed_tools 中的其他工具依然可用,并会继续流转到权限模式这一步。Deny 规则的行为取决于它命名的是整个工具,还是在某个工具内部限定了一个匹配模式(pattern)。
| Option | Effect |
|---|---|
allowed_tools=[\"Read\", \"Grep\"] | Read 和 Grep 被自动批准。未列出的其他工具仍然存在,会继续流转到权限模式和 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__*\"] 会被忽略,并在启动时给出警告,不会自动批准任何东西。
Read 与 Edit 的作用域规则接受一个路径匹配模式(path pattern)。Edit(path) 规则会约束所有会写文件的内置工具,包括 Write 和 NotebookEdit;而 Write(path) 规则永远不会被文件权限检查所匹配到。
绝对文件系统路径请用 //path:deny 规则 Edit(//secrets/**) 会拦截磁盘上 /secrets 目录下任意位置的写入。若只用单个前导斜杠,Edit(/secrets/**) 则会以规则的来源为锚点——对于通过 allowed_tools 或 disallowed_tools 传入的规则,锚点就是会话的工作目录,因此该规则不会拦截磁盘上真正的 /secrets。四种锚定形式及 settings 文件中规则的解析方式,详见 Read and Edit rules。
警告:自动批准的工具永远不会到达
canUseTool。 在更早的步骤中被批准的工具调用——无论是被acceptEdits、bypassPermissions批准,还是被 allow 规则批准——都会跳过你的canUseTool回调,因此你放在回调里的权限检查会被静默绕过。AskUserQuestion、标记了_meta[\"anthropic/requiresUserInteraction\"]的 MCP 工具、被组织设为ask的连接器工具,以及针对关键路径的rm/rmdir删除,即使 allow 规则命中,仍会到达回调。在auto模式下,针对关键路径的删除会走分类器而非回调,上面列出的其他情况仍会到达回调(该分类器路由要求 Claude Code v2.1.218 及以上)。在dontAsk模式下,这些调用会被直接拒绝,不会调用回调。覆盖范围取决于条目的写法:像
Read或mcp__github__get_issue这样的裸名称,会自动批准对该工具的每一次调用(上述例外情况除外);而像Bash(ls *)这样带作用域的规则,只会自动批准匹配的调用,其他Bash调用仍会流转到回调。若需要在每一次工具调用上都强制执行检查,请使用PreToolUsehook:hooks 会在其他所有步骤之前运行,且钩子的拒绝即使在bypassPermissions模式下也依然生效。
若要打造一个「锁死」的 agent,可将 allowedTools 与 permissionMode: \"dontAsk\" 搭配使用。列出的工具会被批准(上文警告中提到的「总是提示」的工具除外);其余一律直接拒绝而不弹出提示:
const options = {
allowedTools: ["Read", "Glob", "Grep"],
permissionMode: "dontAsk"
};
警告:
allowed_tools不会约束bypassPermissions。allowed_tools只是预先批准你列出的工具。未列出的其他工具不会被任何 allow 规则匹配到,会继续流转到权限模式这一步,而bypassPermissions会批准它们。也就是说,同时设置allowed_tools=[\"Read\"]和permission_mode=\"bypassPermissions\",依然会批准所有工具,包括Bash、Write和Edit。如果你需要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 支持以下权限模式:
| Mode | Description | Tool behavior |
|---|---|---|
default | 标准权限行为 | 没有自动批准;未匹配的工具触发你的 canUseTool 回调 |
dontAsk | 拒绝而非提示 | 任何未被 allowed_tools 或规则预先批准的调用都会被拒绝;被组织设为 ask 的连接器工具,以及需要用户交互的工具,即使你已预先批准,也会被拒绝,针对关键路径的 rm/rmdir 删除同样如此。canUseTool 永远不会被调用 |
acceptEdits | 自动接受文件编辑 | 文件编辑及文件系统操作(mkdir、rm、mv 等)会被自动批准 |
bypassPermissions | 绕过权限检查 | 工具运行时不会弹出权限提示,没有任何模式会自动批准的操作除外。请谨慎使用 |
plan | 规划模式 | Claude 探索并制定计划,但不会编辑你的源文件;文件编辑永远不会被自动批准,会通过 canUseTool 回调提示 |
auto | 模型分类批准 | 由一个模型分类器来批准或拒绝权限提示。可用性见 Auto mode |
警告:子代理(Subagent)的继承规则。 子代理会继承父会话的权限模式。
AgentDefinition的permissionMode可以覆盖它,但当父会话使用bypassPermissions、acceptEdits或auto时例外:这三种模式会应用到每一个子代理,无法按子代理单独覆盖。当 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 命令)仍需正常的权限流程。
会被自动批准的操作:
- 文件编辑(
Edit、Write工具) - 文件系统命令:
mkdir、touch、rm、rmdir、mv、cp、sed
以上两类都只适用于工作目录或 additionalDirectories 内的路径。工作目录之外的路径、对受保护路径的写入,以及针对关键路径的 rm/rmdir 删除,仍然会弹出提示。
适用场景: 你信任 Claude 的编辑结果,想要更快的迭代速度,例如在原型开发或在隔离目录中工作时。
Don't ask 模式(dontAsk)
将任何权限提示都转换为拒绝。被 allowed_tools、settings.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 命令(如 touch、rm)也会以同样的方式到达你的 canUseTool 回调。
Claude 在最终确定计划之前,可能会用 AskUserQuestion 来澄清需求。关于如何处理这些提示,见 处理批准与用户输入。
适用场景: 你希望 Claude 只提出变更方案而不实际执行,例如在代码评审阶段,或需要在变更真正生效前先行审批。
相关资源
关于权限评估流程中的其他步骤:
- 处理批准与用户输入:交互式批准提示与澄清问题
- Hooks 指南:在 agent 生命周期的关键节点运行自定义代码
- Permission rules:
settings.json中的声明式 allow/deny 规则