news 2026/9/7 2:50:42

Zed Agent 工具权限完全指南:用 agent.tool_permissions 精细控制 Agent 工具执行

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Zed Agent 工具权限完全指南:用 agent.tool_permissions 精细控制 Agent 工具执行

Zed Agent 工具权限完全指南:用 agent.tool_permissions 精细控制 Agent 工具执行

【免费下载链接】zedCode at the speed of thought – Zed is a high-performance, multiplayer code editor from the creators of Atom and Tree-sitter.项目地址: https://gitcode.com/GitHub_Trending/ze/zed

本文基于 Zed 官方文档 tool-permissions.md 与仓库源码,系统讲解 Zed Agent Panel 中agent.tool_permissions配置项的完整用法:如何为 terminal、edit_file、fetch、MCP 工具等设置自动批准、自动拒绝与强制确认规则,并结合 权限决策引擎 的源码剖析规则优先级、shell 链式命令解析、内置安全规则等底层机制,帮助你把 Agent 的自动化程度调到“既省心又安全”的平衡点。

版本说明:从布尔开关到规则引擎

在 Zed v0.224.0 及以上版本中,工具审批由agent.tool_permissions.default及其嵌套规则控制。更早的版本中,该行为由布尔值agent.always_allow_tool_actions(默认false)控制。本文所有内容以当前仓库(即 v0.224.0 之后)的实现为准。

相关背景可参阅 Agent Panel 文档 与 工具列表文档。

快速开始

可以用 Zed 的 Settings Editor 配置工具权限(agent.tool_permissions设置页),也可以直接编辑设置文件。下面的示例让cargonpm命令自动放行,而sudo命令逐次确认:

{ "agent": { "tool_permissions": { "default": "allow", "tools": { "terminal": { "default": "confirm", "always_allow": [ { "pattern": "^cargo\\s+(build|test|check)" }, { "pattern": "^npm\\s+(install|test|run)" } ], "always_confirm": [{ "pattern": "sudo\\s+/" }] } } } } }

该示例的效果:

  • terminal工具内的cargo/npm命令自动批准;
  • sudo命令无论全局default如何都会逐次弹出确认;
  • 非 terminal 类工具遵循全局"default": "allow",但工具级defaultalways_confirm规则仍然可以触发提示。

工作原理

tool_permissions通过正则模式对每次工具调用的输入进行匹配,实现三类语义:

  • 自动批准always_allow):放行你信任的操作;
  • 自动拒绝always_deny):直接拦截危险操作——即使tool_permissions.default设为"allow"也会被阻止;
  • 强制确认always_confirm):无论其他设置如何,命中即弹确认。

支持的工具与匹配对象

不同工具的权限规则作用于不同的“输入文本”,这是写模式前必须理解的一点:

工具正则匹配的对象
terminalShell 命令字符串
edit_file文件路径
write_file文件路径
delete_path被删除的路径
move_path源路径与目标路径
copy_path源路径与目标路径
create_directory目录路径
fetchURL
search_web搜索查询词
skill该 skill 的SKILL.md文件的绝对路径

两个特例:

  • MCP 工具使用mcp:<server>:<tool_name>格式作为工具名。例如github服务器上的create_issue工具写作mcp:github:create_issue
  • Skills:模型自主调用的 skill 走skill工具权限;而你通过/skill-name斜杠命令手动触发的 skill 不会再次弹确认(因为是你显式调用的)。

完整配置参考

tool_permissions的完整结构如下(字段定义见 settings 内容类型):

{ "agent": { "tool_permissions": { "default": "confirm", "tools": { "<tool_name>": { "default": "confirm", "always_allow": [{ "pattern": "...", "case_sensitive": false }], "always_deny": [{ "pattern": "...", "case_sensitive": false }], "always_confirm": [{ "pattern": "...", "case_sensitive": false }] } } } } }

字段语义

字段说明
default所有模式都不命中时的兜底模式:"confirm"(默认)、"allow""deny"
always_allow命中即自动批准的规则(除非同时命中 deny 或 confirm)
always_deny命中即立即拦截——最高优先级,不可被覆盖
always_confirm命中即总是弹确认,即使全局default"allow"

工具级的default未设置时,继承全局tool_permissions.default

模式语法

{ "agent": { "tool_permissions": { "tools": { "edit_file": { "always_allow": [ { "pattern": "your-regex-here", "case_sensitive": false } ] } } } } }

模式的两个关键属性,均可从源码确认:

  • Rust regex 语法:模式经regex::RegexBuilder编译,实现在 CompiledRegex;
  • 默认不区分大小写case_sensitive默认false,即case_insensitive(!case_sensitive)(源码位置)。单元测试case_insensitive_by_default验证了CARGO TEST可命中cargo模式(测试位置)。

另外注意 settings 层注释:always_allow/always_deny/always_confirmExtendingVec类型,规则会跨设置层(user、project、profile)累积,高优先级层只能追加、不能移除低层规则——在 monorepo 中用项目级设置补充 deny 规则时这一点尤其重要。

无效正则的“熔断”行为

从源码可以看到一个防御性设计:若某工具下有任何一条模式编译失败,该工具的所有调用都会被直接拒绝,而不是静默跳过坏规则。见 check_invalid_patterns:错误信息会列出失效模式数量,提示你去修正tool_permissions。对应测试invalid_pattern_blocks(位置)验证了这一点。

规则优先级:六级裁决的真实执行顺序

文档声明的优先级(从高到低):

  1. 内置安全规则:硬编码保护(如rm -rf /),任何设置都无法覆盖;
  2. always_deny:拦截命中动作;
  3. always_confirm:要求确认;
  4. always_allow:自动批准;
  5. 工具级default(如tools.terminal.default);
  6. 全局defaulttool_permissions.default)。

这与 ToolPermissionDecision::from_input 的实现完全对应,其执行流程可以概括为:

  1. 先查内置安全规则(仅 terminal 工具有),命中即Deny,消息固定为 "Blocked by built-in security rule...";
  2. 检查无效正则,存在即Deny
  3. terminal 特判:若命令包含$VAR$(...)、反引号等 shell 替换/插值,且该工具不是“无条件全放行”状态(无 deny/confirm 规则且有效 default 为 allow),则直接Deny,因为带变量展开的命令无法静态校验(源码位置);
  4. 进入 check_commands 单遍评估,其逻辑是:
    • DENY 短路:任意一条子命令命中 deny 模式立即返回Deny
    • CONFIRM 累积:任意子命令命中 confirm 模式则标记待确认;
    • ALLOW 需全中:所有子命令都必须至少命中一条 allow 模式才返回Allow
    • 否则落到rules.default.unwrap_or(global_default)

check_commands的这个“deny 任一命中即拦截、allow 必须全部命中”的不对称设计,是防止链式命令(ls && rm -rf /)绕过白名单的核心,仓库中有专门的注入防护测试族验证(shell 注入测试:&&;|||、反引号、$(...)、后台&、换行符等各种串联方式都不会让^ls白名单误放行)。

Terminal 工具深度解析:Shell 兼容性与解析策略

文档的 Shell Compatibility 一节说明:对terminal工具,Zed 会解析链式命令(如echo hello && rm file),把每个子命令分别拿去匹配你的模式;支持的 shell 包括 sh、bash、zsh、dash、fish、PowerShell 7+、pwsh、cmd、xonsh、csh、tcsh、Nushell、Elvish 与 rc(Plan 9)。

源码里(from_input 的 terminal 分支)还有几个值得注意的细节:

  • 解析失败 = 禁用 allow:若命令无法被解析(brush-parser),allow_enabled置为false,即该命令的always_allow不生效,回落到 default/确认;测试parse_failure_is_denied"ls &&"这类残缺命令)验证了这一点;
  • 重定向智能处理2>/dev/null这类安全重定向在提取子命令时被跳过,不会妨碍白名单命中(dev_null_redirect_does_not_cause_false_negative 测试),而echo hello > /etc/passwd这样的真实文件重定向仍会阻止自动放行;
  • 管道命令逐段校验echo "y\ny" | git add -p file拆成两个子命令,两边都命中 allow 模式才自动批准;
  • 环境前缀命令PAGER=blah git log这类写法需要模式显式匹配前缀(^PAGER=blah\s+git\s+log(\s|$)),旧的^git\b模式不再命中(对应测试)。

内置安全规则:不可覆盖的底线

Zed 内置了一小组任何设置都无法覆盖的硬编码安全规则,只作用于 terminal 工具,用于阻止对关键目录的递归删除:

  • rm -rf /rm -rf /*—— 文件系统根;
  • rm -rf ~rm -rf ~/*—— 主目录;
  • rm -rf $HOME/rm -rf ${HOME}(含$HOME/*)—— 环境变量形式的主目录;
  • rm -rf .rm -rf ./*—— 当前目录;
  • rm -rf ..rm -rf ../*—— 父目录。

这些规则会捕获任意 flag 组合(-fr-rfv-r -f--recursive --force),且大小写不敏感;同时对原始命令与链式命令中解析出的每个子命令做检查(如ls && rm -rf /)。除此之外没有其他内置规则。

从源码 HARDCODED_SECURITY_RULES 可以看到其实现比文档描述更“抗绕过”:

  • flag 正则同时覆盖短 flag(-[a-zA-Z]+)、长 flag 及--flag=value形式,且通过TRAILING_FLAGS允许 GNU rm 的“flag 放在路径之后”写法(rm / -rf);
  • matches_hardcoded_patterns 对rm命令做多路径展开 + 路径归一化rm -rf /tmp /(多路径中含危险项)与rm -rf /tmp/../../(路径穿越)都会被归一化后命中;
  • 测试hardcoded_cannot_be_bypassed_by_globalhardcoded_cannot_be_bypassed_by_allow_pattern(位置)验证了:即使全局default: allow或配置了always_allow: [".*"]rm -rf /依然被拒;
  • 安全路径不受误伤:rm -rf ./buildrm -rf ~/Documentsrm -rf /tmp/test在全放行模式下可正常通过(hardcoded_allows_safe_rm)。

默认设置文件 default.json 中的tool_permissions段落包含了注释掉的示例(保护.env、secrets 目录、私钥等),可以按团队需要取消注释或改写。

全局自动批准

若希望所有工具动作自动通过:

{ "agent": { "tool_permissions": { "default": "allow" } } }

这会绕过多数工具的确认弹窗,但以下情形仍会提示或拦截:always_deny规则、always_confirm规则、内置安全规则,以及位于 Zed 设置目录内的路径。

源码侧对应一个“无条件全放行”判断 is_unconditional_allow_all:仅当无 deny/confirm 规则且有效 default 为 allow 时,terminal 的“含 shell 替换即拒绝”检查也会被跳过(对应测试)——即你显式声明“全放行”后,Zed 不再对echo $HOME这类命令额外设防,但仍拦不住内置的rm -rf /类规则(测试)。

路径工具的防穿越:双重判定

对基于路径的工具(edit_file、delete_path、copy_path、move_path 等),Zed 使用 decide_permission_for_paths 而非简单的单次匹配:

  1. 先对原始路径做一次权限判定;
  2. 再用 normalize_path 折叠./..段得到归一化路径,做第二次判定(不触碰文件系统);
  3. 用 most_restrictive(Deny > Confirm > Allow)取两者中最严格的结果。

这意味着src/../.env这类写法无法绕过针对^\.env的 deny 规则——测试族 覆盖了穿越到/etc/passwd.zed/.env等多种场景。

权限请求 UI 中的操作

当 Agent 请求权限时,线程视图中的工具卡片会带一个菜单:

  • Allow once / Deny once:一次性决定;
  • Always for <tool>:把tools.<tool>.default设为 allow 或 deny;
  • Always for <pattern>:在能安全抽取模式时,为该输入追加一条always_allowalways_deny规则;
  • MCP 工具只支持工具级选项(无 pattern 抽取)。

“Always for <pattern>”抽取出的模式是子命令级精确的:测试 always_allow_button_works_end_to_end 验证了从cargo build --release抽取的模式会放行cargo build --features foo,但不会放行cargo testcargo build-foo(插件前缀)或npm install

实战示例集

以下示例完整继承自官方文档,可直接复制到设置文件。

Terminal:自动批准构建命令

{ "agent": { "tool_permissions": { "tools": { "terminal": { "default": "confirm", "always_allow": [ { "pattern": "^cargo\\s+(build|test|check|clippy|fmt)" }, { "pattern": "^npm\\s+(install|test|run|build)" }, { "pattern": "^git\\s+(status|log|diff|branch)" }, { "pattern": "^ls\\b" }, { "pattern": "^cat\\s" } ], "always_deny": [ { "pattern": "rm\\s+-rf\\s+(/|~)" }, { "pattern": "sudo\\s+rm" } ], "always_confirm": [ { "pattern": "sudo\\s" }, { "pattern": "git\\s+push" } ] } } } } }

文件编辑:保护敏感文件

{ "agent": { "tool_permissions": { "tools": { "edit_file": { "default": "confirm", "always_allow": [ { "pattern": "\\.(md|txt|json)$" }, { "pattern": "^src/" } ], "always_deny": [ { "pattern": "\\.env" }, { "pattern": "secrets?/" }, { "pattern": "\\.(pem|key)$" } ] } } } } }

路径删除:阻断关键目录

{ "agent": { "tool_permissions": { "tools": { "delete_path": { "default": "confirm", "always_deny": [ { "pattern": "^/etc" }, { "pattern": "^/usr" }, { "pattern": "\\.git/?$" }, { "pattern": "node_modules/?$" } ] } } } } }

URL 抓取:控制外网访问

{ "agent": { "tool_permissions": { "tools": { "fetch": { "default": "confirm", "always_allow": [ { "pattern": "docs\\.rs" }, { "pattern": "github\\.com" } ], "always_deny": [{ "pattern": "internal\\.company\\.com" }] } } } } }

MCP 工具

{ "agent": { "tool_permissions": { "tools": { "mcp:github:create_issue": { "default": "confirm" }, "mcp:github:create_pull_request": { "default": "confirm" } } } } }

Skills

skill工具的模式匹配的是该 skillSKILL.md绝对路径,而不是 skill 名称:

{ "agent": { "tool_permissions": { "tools": { "skill": { "default": "confirm", "always_allow": [{ "pattern": "/code-review/SKILL\\.md$" }] } } } } }

要彻底禁止模型调用某个 skill,请在该 skill 的SKILL.md中设置disable-model-invocation: true(见 Skills 文档)。

编写模式的技巧与测试方法

  • \b做单词边界:\brm\b匹配 "rm" 但不匹配 "storm";
  • ^$将模式锚定到输入首/尾;
  • 转义特殊字符:字面点号写\.,反斜杠写\\
  • 链式命令中 allow 需要每个子命令都命中——白名单要按“最细粒度命令”来写,而不是按整条流水线。

注意:deny 模式里一个笔误就会误伤合法操作。每个工具的设置页提供 “Test Your Rules” 检查器(实现见 tool_permissions_setup.rs),可以先验证某条命令会落入哪个判定分支再落盘规则。

小结与源码索引

agent.tool_permissions用“六层优先级 + 正则规则 + 不可覆盖的内置底线”三层结构,在 Agent 自动化与操作安全之间给出可精细调节的旋钮。阅读源码建议按以下路径:

  • crates/agent/src/tool_permissions.rs:决策引擎ToolPermissionDecision::from_input、内置安全规则、shell 子命令解析、路径归一化,以及覆盖注入防护/穿越绕过/多路径展开的大规模测试;
  • crates/agent_settings/src/agent_settings.rs:ToolPermissionsToolRulesCompiledRegex(regex 编译与大小写语义)、无效正则的InvalidRegexPattern结构;
  • crates/settings_content/src/agent.rs:设置文件层面的ToolPermissionsContent/ToolRulesContent/ToolRegexRuleToolPermissionMode枚举(allow/deny/confirm,默认 confirm),以及跨设置层累积的注释说明;
  • assets/settings/default.json:tool_permissions默认值与注释示例。

【免费下载链接】zedCode at the speed of thought – Zed is a high-performance, multiplayer code editor from the creators of Atom and Tree-sitter.项目地址: https://gitcode.com/GitHub_Trending/ze/zed

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/7 2:50:34

JavaEE订餐系统课程设计实战:从数据库建模到部署答辩要点

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/7 2:49:37

多项式与有理函数:微积分预备的核心与Python验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/7 2:49:36

C++动态测试实战:从Google Test到ASan内存检测全攻略

简介&#xff1a;面向软件测试课程学习者与C开发者&#xff0c;该实验报告基于Parasoft C Test 9.2环境&#xff0c;完整演示了动态测试的实施流程。报告依次介绍动态测试方法、自动化单元测试用例生成与执行、自定义测试用例向导配置、基于CSV数据源批量创建测试用例&#xff…

作者头像 李华
网站建设 2026/9/7 2:46:56

嵌入式启动流程、故障定位与OTA升级:从底层硬功夫到工程化实战

最近把一个从同事手里移交过来的板子调通&#xff0c;板子本身不复杂&#xff0c;但上电后动不动就卡死在某个外设初始化里&#xff0c;偶尔又能正常跑起来&#xff0c;很典型的启动流程问题。后来花了半天时间把启动各阶段全部理清楚&#xff0c;问题根源其实是一个外设在复位…

作者头像 李华