05. 权限、计划与安全
权限规则与钩子拦截
模式决定 Matcha CLI 问你的频率。规则和钩子为特定工具、路径和命令设下常驻的是 / 问 / 否。
授权顺序
一次工具调用按这个顺序授权:
PreToolUse钩子。钩子明确deny会在任何权限检查之前拦住调用。钩子allow不会跳过后面的检查;它只是表示自己不拒绝。- 权限规则(
deny>ask>allow),从每个来源合并。deny胜过允许,也胜过始终批准的正常放行。 - 此前卡片记住的授权(
remember_tool_approvals打开时),限定在这个项目。 - 内置自动批准(只读工具和只读命令列表)。
- 当前模式的询问策略(询问 / 自动 / 始终批准 /
dontAsk)。
始终批准在第 2 步之后短路:拒绝规则、钩子和 shell 片段的 ask 规则仍然生效;记住的授权会被跳过。
规则写在哪
规则来自若干文件,合并成一套。谁赢看严重程度,不看来源文件。
| 范围 | 文件 |
|---|---|
| 全局 | ~/.matcha/config.toml |
| 项目(可共享) | <project>/.matcha/config.toml(从仓库根到当前工作目录的每一层) |
| 项目(个人) | <project>/.claude/settings.local.json |
| 托管 | /etc/matcha/managed_config.toml、~/.matcha/managed_config.toml |
| CLI | --allow RULE、--deny RULE(可重复) |
没有原生的 config.local.toml。交互里的「始终允许」决定存在仓库外面,按项目保存。
规则语法
原生结构化写法:
[permission]
rules = [
{ action = "allow", tool = "bash", pattern = "git *" },
{ action = "deny", tool = "bash", pattern = "rm -rf *" },
{ action = "ask", tool = "edit" },
]紧凑字符串写法(与 --allow / --deny 以及 Claude 设置同一套语言):
[permission]
allow = ["Bash(git *)", "Grep"]
deny = ["Bash(rm -rf *)"]结构化写法里的 tool 名是小写:bash、read、edit、grep、mcp、webfetch、websearch。字符串规则用 Bash、Read、Edit / Write、Grep / Glob、MCPTool、WebFetch、WebSearch。单独一个 * 匹配所有工具。
规则在会话开始时读取。改文件后,再开新会话。
这里相关的钩子是 PreToolUse。项目钩子需要目录信任(/hooks-trust 或 --trust)。~/.matcha/hooks/ 里的全局钩子始终受信任。钩子安装和完整生命周期见「扩展 Matcha」。
什么时候用规则和钩子
给每天跑的命令(git、cargo test)写一条窄的 allow,询问模式就会安静下来。对绝不能跑的路径和命令用 deny,包括始终批准之下。策略是「只许这些前缀,每种模式都算,包括我没法写成一条 glob 的命令链」时,用 PreToolUse 钩子。
给项目加允许 / 拒绝
# .matcha/config.toml
[permission]
allow = ["Bash(cargo test *)", "Bash(npm run build)"]
deny = ["Bash(rm -rf *)"]matcha -p "Review the API changes" \
--allow 'Bash(git *)' \
--deny 'Bash(rm -rf *)'Bash(git *) 是前缀加 glob(末尾空格加 * 让 git 保持整词)。Bash(git) 也会匹配 gitleaks。匹配区分大小写。
命令链
deny 和 ask 检查每一段(&&、||、;、|)以及整串。一段被拒绝,整条命令就被拒绝。allow 只匹配整串,所以 Bash(git *) 会放行 git status && rm -rf /。窄的允许要配上拒绝。
无界面且设硬底线
matcha -p "Implement the feature using only git and GitHub CLI" \
--allow 'Read' \
--allow 'Grep' \
--allow 'Bash(git *)' \
--allow 'Bash(gh *)'对没有 allow 的工具做默认拒绝,用 Claude 的 defaultMode: "dontAsk" 或 PreToolUse 钩子。不能在 bash 上叠一条通配 deny 再旁边 allow git——拒绝会赢,git 也会被拦住。
钩子拒绝
PreToolUse 钩子可以在每种权限模式里拦住调用。例如:~/.matcha/hooks/git-gh-only.json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "git-gh-only.sh", "timeout": 5 }
]
}
]
}
}脚本从标准输入读 JSON(toolInput.command),写出 {"decision":"deny","reason":"…"} 并以退出码 2 结束,或写出 {"decision":"allow"}。命令链要自己拆;钩子运行器不会替你拆。匹配器 Bash 也会匹配真实工具名 run_terminal_command。
用 /hooks 安装和查看(非 VS Code 家族终端上用 Ctrl+L)。按 r 从磁盘重新加载。
和沙箱一起用
面对不信任的代码:
dontAsk加上窄的允许,或一条限制性的PreToolUse钩子--sandbox strict(或带deny的自定义配置档)- 在任何
SessionStart/ 项目钩子跑之前先做项目信任
在 TUI 里
权限决定出现在记录里。/always-approve 和 /auto 改的是模式,不是规则文件。/hooks 管理钩子来源。