本教程聚焦一个被广泛误解的 Claude Code Skills 机制:allowed-tools 并不限制工具访问。很多人以为在 frontmatter 里写 allowed-tools: Read Grep 就能把 Skill 锁成只读沙箱——事实并非如此。读完本文,你将掌握 Skill 的完整权限治理模型,学会用 disallowed-tools、paths、disable-model-invocation 三字段给自定义技能上真正的锁,并能识别"项目级 Skill 自授广权限"这一团队安全陷阱。适合已经写过基础 Skill、希望把技能安全地引入团队或生产流程的开发者。
SKILL.md 的基本结构(frontmatter + Markdown 正文)settings.json 权限规则(allow / ask / deny)的基本概念allowed-tools 不是白名单这是整篇文章最重要的一段,请先记住这句话:
allowed-tools授予权限(免确认),不限制可用工具。真正的限制要用disallowed-tools。
官方文档原文写得很清楚:"allowed-tools 字段在 Skill 激活期间,为列出的工具授予许可,让 Claude 无需逐次征求批准即可使用。它并不限制哪些工具可用:每个工具依然可以被调用,未被列出的工具仍受你的权限设置管辖。"
换句话说,下面这段配置是一个极其常见的误解:
---
name: my-reader
description: 只读分析工具
allowed-tools: Read Grep
---
很多人的心智模型是:"这个 Skill 只能用 Read 和 Grep,是个白名单。" 实际行为是:Read 和 Grep 会被预批准(不再弹确认框),但 Write、Edit、Bash 这些工具依然全部可用——只是它们会走正常的权限确认流程。如果用户处于宽松的权限模式(比如 acceptEdits),这个"只读"Skill 照样能改文件。
社区甚至有专门的 issue 在讨论这个反直觉行为:标题就叫《allowed-tools in SKILL.md frontmatter does not restrict tool access》。这不是 bug,而是设计:allowed-tools 的语义是"预批准 / 静默许可",不是"隔离 / 白名单"。
理解这一点后,权限治理的思路就清晰了:要禁止,用 disallowed-tools;要预批准,用 allowed-tools;要限定何时激活,用 paths;要控制谁能触发,用 disable-model-invocation 与 user-invocable。
先把治理工具箱摆全。下表是官方支持的、与权限/激活相关的 frontmatter 字段(全部可选):
| 字段 | 作用 | 默认 | 关键语义 |
|---|---|---|---|
allowed-tools |
预批准(免确认) | 继承会话权限 | 授予许可,不限制 |
disallowed-tools |
从工具池移除 | 无 | 真限制;下一条消息后清除 |
paths |
限定自动激活的文件范围 | 无(任意文件都触发) | glob 模式,命中才加载 |
disable-model-invocation |
阻止 Claude 自动触发 | false |
设为 true 后仅人工 /name 调用 |
user-invocable |
是否出现在 / 菜单 |
true |
设为 false 后仅 Claude 自动调用 |
此外,context: fork + agent 可把 Skill 放进隔离的子智能体上下文执行,model / effort 可在 Skill 激活期间临时切换模型与算力档位——这些虽不直接是"权限",但都属于"Skill 激活期间的行为控制",可配合权限字段一起设计。
disallowed-tools:真正的围栏disallowed-tools 会把列出的工具从 Claude 的可用工具池中移除,是 frontmatter 层面唯一的"硬禁止"机制。注意它的一个重要特性:限制在你发送下一条消息后清除——它不是会话级的永久封锁,而是"当前这轮 Skill 任务"内的临时禁用。
---
name: audit-only
description: 只读审计,绝不允许修改文件
disable-model-invocation: true
disallowed-tools: Write Edit NotebookEdit
allowed-tools: Read Grep Glob
---
这个配置的效果:
Read Grep Glob 被预批准 → 读取、搜索全程无确认框,体验流畅Write Edit NotebookEdit 被移除 → 即使 Claude 想"顺手帮你修个 bug",工具根本不在池里,调用直接失败disable-model-invocation: true → 只有你手动 /audit-only 才会跑,Claude 不会自作主张这就构成了一个语义上真正的"只读 Skill":预批准只读 + 硬禁止写入 + 手动触发。
paths:把激活范围钉死在特定文件disallowed-tools 解决"能做什么",paths 解决"何时激活"。它接受 glob 模式(逗号分隔字符串或 YAML 列表),格式与 CLAUDE.md 的 path-specific 规则一致。设置后,Claude 只有在你操作的文件命中模式时才会自动加载该 Skill。
---
name: sql-migration-review
description: 审查 SQL 迁移脚本中的破坏性操作
paths: db/migrations/**/*.sql, migrations/*.sql
disallowed-tools: Write Edit
---
效果:你编辑 README.md 时它沉默不加载(省 token);你一打开 db/migrations/2026_06_drop_users.sql,它立刻进入待命,准备审查 DROP TABLE、DELETE 无 WHERE 这类高危语句。
常见坑:paths 只影响"Claude 自动加载"的时机;如果你手动 /sql-migration-review 强制调用,无论当前在编辑什么文件它都会跑。paths 是"自动触发的闸门",不是"调用的闸门"。
| 配置 | 你能调用 | Claude 能调用 | 何时进上下文 |
|---|---|---|---|
| (默认) | 是 | 是 | description 常驻;调用后载入全文 |
disable-model-invocation: true |
是 | 否 | description 也不进上下文 |
user-invocable: false |
否 | 是 | description 常驻 |
经验法则:
/commit、/deploy、/publish)→ disable-model-invocation: true。你不希望 Claude 觉得"代码看起来准备好了"就自己部署。user-invocable: false。/legacy-system-context 不是一个有意义的用户动作,但你希望 Claude 在相关时自动知晓。precommit-audit 提交前自审 Skill下面构建一个完整、可运行的 Skill:在提交前扫描暂存区,审计硬编码密钥、调试残留、TODO/FIXME、缺少测试等问题。它必须严格只读——只能看、不能改、更不能替你提交。
目录结构:
.claude/skills/precommit-audit/
├── SKILL.md # 入口 + 治理字段(必需)
└── reference.md # 详细检查规则(按需加载)
---
name: precommit-audit
description: 提交前只读自审。扫描暂存区改动,报告硬编码密钥、调试残留、TODO/FIXME、缺少测试等问题。Use when the user is about to commit, asks to review staged changes, or says "提交前检查一下".
disable-model-invocation: true
disallowed-tools: Write Edit NotebookEdit
allowed-tools: Read Grep Glob Bash(git status:*) Bash(git diff:*) Bash(git log:*)
paths: "**/*"
---
## 暂存区上下文(动态注入,运行前已替换为真实输出)
- 待提交文件清单:!`git diff --cached --name-only`
- 完整暂存差异:!`git diff --cached`
## 任务
只读分析上面的差异,按 `reference.md` 的检查清单逐项核对,输出一份结构化报告。**严禁修改任何文件、严禁执行 git add/commit**——你没有写入工具,也不应该尝试绕过。
报告格式:
1. **🔴 高危**:硬编码密钥 / credentials / `.env` 内容被提交
2. **🟡 警告**:`console.log` / `print` / `debugger` 等调试残留
3. **🔵 提示**:未解决的 TODO/FIXME、缺少对应测试的新函数
4. **✅ 通过项**:本次改动中表现良好的实践
若暂存区为空,直接回复"没有待提交的改动"。
## 补充规则
- 完整检查项与示例见 [reference.md](reference.md),仅当差异中涉及该类问题时加载。
注意这几处设计的用意:
!git diff --cached`` 用动态上下文注入:命令在 Claude 看到正文之前就执行完毕,输出替换占位符。Claude 收到的是真实 diff,而不是"去跑一下 git diff"的指令——这把"可能跑错命令"的风险降到了零。allowed-tools 只预批准只读类 git 子命令(用 Bash(git status:*) 精确匹配,而非 Bash(git:*) 全量放行),所以即便想跑也不会被预批准 git commit。disallowed-tools: Write Edit NotebookEdit 保证文件绝不被改。disable-model-invocation: true 保证只有你敲 /precommit-audit 才会触发。# precommit-audit 详细检查清单
## 高危(必须拦截)
- `password = "..."`、`api_key = "..."`、`AKIA[0-9A-Z]{16}`(AWS key)
- 私钥头 `-----BEGIN ... PRIVATE KEY-----`
- 内网 IP、数据库连接串、JWT secret
## 警告(建议拦截)
- `console.log` / `print(` / `debugger` / `dd(` / `var_dump(`
- 注释掉的大段代码
## 提示(酌情提醒)
- 新增 public 函数但仓库内无对应测试文件
- `TODO` / `FIXME` / `XXX` 标记
为什么把清单拆出去?官方 Tip 是"SKILL.md 控制在 500 行以内,详细参考材料移到独立文件"。一旦 Skill 被调用,正文会常驻上下文直到会话结束,每一行都是反复消耗的 token 成本。把不常用的细节放进 reference.md,只在正文里写"命中时再加载",平时几乎零成本。
在一个有暂存改动的仓库里:
/precommit-audit
预期 Claude 输出一份分级报告,且全过程不弹出任何文件写入确认框(因为没有写入工具),不触发提交。如果你发现它居然改了文件,那说明 disallowed-tools 没生效——见第七节排错。
一个常见的困惑:"我上篇用 hooks 做过提交守卫,这里又用 Skill 做自审,两者什么关系?" 区别如下:
| 维度 | Hooks(settings.json) | Skill(SKILL.md) |
|---|---|---|
| 执行者 | Claude Code 框架,确定性地 | Claude 模型,按指令编排 |
| 触发 | 事件驱动(PreToolUse、Stop 等) | 手动 /name 或语义自动 |
| 可解释性 | 脚本输出,机械 | 自然语言报告,可对话追问 |
| 适合 | 硬性规则("禁止提交含密钥") | 软性建议("这里有 3 处可疑,你看下") |
实践上两者互补:用 hooks 做确定性闸门(哪怕 Claude 想提交也会被脚本拦下),用 Skill 做可解释的预审(提交前先 /precommit-audit 看一眼报告,决定要不要修)。本文聚焦 Skill 这一路。
下图展示 Skill 从休眠到激活、再到每次工具调用如何被治理的完整链路:
flowchart TD
U[用户提问 / 编辑文件] --> M{匹配 description<br/>且 paths 命中?}
M -->|是| L[加载 SKILL.md 进上下文<br/>激活权限层]
M -->|否| S[保持休眠 不占 token]
L --> T[模型发起工具调用]
T --> C{工具在 allowed-tools?}
C -->|是| D[免确认放行]
C -->|否| E{工具在 disallowed-tools?}
E -->|是| F[工具已移出池 调用失败]
E -->|否| G[走 settings.json 权限规则]
G --> R{allow / ask / deny}
R -->|allow| D
R -->|ask| H[弹确认框]
R -->|deny| F
H -->|批准| D
H -->|拒绝| F
D --> N[继续执行]
F --> N
N --> NEXT[发送下一条消息:<br/>disallowed-tools 清除]
Q1:我写了 allowed-tools: Read,为什么 Claude 还是能调用 Write?
因为 allowed-tools 只预批准、不限制。要禁止写,请加 disallowed-tools: Write Edit。
Q2:disallowed-tools 似乎过了一会儿就失效了?
这是设计。它在"下一条用户消息"后清除,属于当前任务轮次内的临时禁用,不是会话级封锁。需要长期禁止某工具,请用 settings.json 的 deny 规则。
Q3:项目级 .claude/skills/ 里写了 allowed-tools,但 Skill 跑起来还是反复弹确认。
项目级 Skill 的 allowed-tools 要在你接受该目录的工作区信任对话框(workspace trust dialog)后才生效,与 .claude/settings.json 的权限规则同理。检查是否已信任该仓库。
Q4:paths 设了,但在别的文件里手动 /skill 还是能跑?
对。paths 只控制"自动加载"的时机,手动调用不受限。如需禁止在特定路径调用,得靠 disallowed-tools 或权限规则。
Q5:Bash 怎么做"只读"?我不想让 Skill 跑 rm。
frontmatter 对 Bash 是粗粒度的:disallowed-tools: Bash 会一刀切禁掉所有 bash(连 git status 也不行)。正确做法是用 allowed-tools 精确预批准只读子命令(Bash(git status:*)、Bash(git diff:*)),其余 bash 走 settings.json 的 deny 规则(如 Bash(rm:*))。细粒度 bash 治理仍依赖 settings.json,frontmatter 是粗筛。
官方文档有一条容易被忽视的安全警告:对于提交进项目 .claude/skills/ 的 Skill,allowed-tools 在你接受信任对话框后才生效,而一个 Skill 可以为自己授予很宽的工具访问权限。这意味着:
SKILL.md 的 allowed-tools / disallowed-tools。一个写着 allowed-tools: Bash(*) 的 Skill 等于把无确认 shell 交了出去。deny 规则,可以兜底覆盖任何 Skill 的 allowed-tools——因为 disallowed-tools 和 settings 的 deny 才是硬限制,allowed-tools 绕不过它们。disable-model-invocation: false + 宽 allowed-tools 的 Skill,可能在你不注意时被 Claude 自动激活并执行副作用操作。记住这条治理优先级链:settings.json deny > disallowed-tools > allowed-tools(仅预批准)。要构建真正不可越界的 Skill,从链的两端同时设防。
code.claude.com/docs/en/skills):本文所有字段语义的权威来源,含动态上下文注入、子智能体执行、$ARGUMENTS 替换等进阶特性。anthropics/claude-code 仓库 plugins/plugin-dev/skills/command-development/references/frontmatter-reference.md):allowed-tools、model、argument-hint 每个字段的格式与最佳实践。code.claude.com/docs/en/tools-reference):每个工具的权限要求,配合设计 allowed-tools / disallowed-tools 时查阅。agentskills.io):Claude Code Skills 遵循的跨工具标准,了解可移植性边界。precommit-audit 40 分钟 + 排错与团队策略讨论 20 分钟,合计约 85 分钟。allowed-tools 与 disallowed-tools 的语义差异;能否独立设计一个"预批准只读 + 硬禁止写入 + 限定 paths + 手动触发"的治理完备 Skill;能否识别并审查陌生仓库 Skill 的权限风险。allowed-tools、model、argument-hint 字段格式与 Bash 命令过滤语法的出处allowed-tools 不限制工具访问"这一反直觉行为的设计本质allowed-tools / disallowed-tools 与 settings.json 规则时查阅[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。
