
用了 Claude Code 一段时间,有件事让我很头疼。
每次让它帮我写完一段代码,它要问我一句"能不能保存文件"。跑个测试,又问一句。创建个目录,再问一句。本来是来解放双手的,结果变成了另一种形式的"人肉确认机器"。
直到我彻底搞懂了它的权限配置系统,这个问题才真正解决。
为什么 Claude Code 会不断打断你
Claude Code 的设计哲学是谨慎优先。它默认对几乎所有文件操作、终端命令都会暂停下来问你一句,因为 AI 执行出错的代价,可能比慢一点高得多。
这个设计是对的。
但问题在于,"谨慎"和"高频打断"之间有巨大的差距。git status 这种只读命令,swift build 这种本地构建,根本不需要每次确认。真正需要谨慎的,是 git push、npm install、以及任何涉及破坏性的操作。
Claude Code 提供了一套精细的权限配置机制,让你自己来划这条线。
权限系统的三个层级
配置文件有三层,从全局到局部依次覆盖:
~/.claude/settings.json ← 全局,所有项目生效
<项目>/.claude/settings.json ← 项目级,可提交到 git
<项目>/.claude/settings.local.json ← 项目本地,加入 .gitignore
优先级:项目本地 > 项目级 > 全局。权限规则是合并生效的,但 deny 永远是最高优先级,任何地方的 deny 规则都不会被覆盖。
实际用法很清晰:
- 全局配置放通用规则(git 操作、构建工具、读文件)
- 项目配置放这个项目专属的规则(iOS 项目放 xcodebuild,前端项目放 vite)
- 本地配置放个人习惯、或者不适合提交的临时规则

权限配置的结构
settings.json 里的 permissions 字段,包含三个数组:
{
"permissions": {
"allow": [], // 自动执行,不询问
"ask": [], // 执行前暂停,等你确认
"deny": [] // 完全禁止,拒绝执行
}
}
规则格式是 操作类型(匹配模式),支持通配符:
| 操作类型 | 说明 | 示例 |
|---|---|---|
Bash |
终端命令 | Bash(git status) |
Edit |
修改已有文件 | Edit(src/**/*.ts) |
Write |
创建新文件 | Write(src/**/*.tsx) |
Read |
读取文件 | Read(README.md) |
WebFetch |
抓取网页 | WebFetch(domain:github.com) |
冒号在 Bash 规则里有特殊含义:Bash(git log:*) 表示允许 git log 加任意参数,而 Bash(git log) 只允许不带参数的裸命令。这个细节很容易忽略,但影响很大。
一份真正好用的全局配置
下面这份配置,是我在 iOS + Vue/TypeScript 的开发栈上磨合出来的版本。
核心策略:读操作全放行,源码编辑按路径放行,写操作和构建命令按风险分级,破坏性操作一律 deny。
{
"permissions": {
"allow": [
"Bash(git status)",
"Bash(git log:*)",
"Bash(git diff:*)",
"Bash(git add:*)",
"Bash(git stash:*)",
"Bash(git branch:*)",
"Bash(git switch:*)",
"Bash(git checkout:*)",
"Bash(swift build:*)",
"Bash(swift test:*)",
"Bash(swift run:*)",
"Bash(xcodebuild:*)",
"Bash(npm test:*)",
"Bash(npm run lint:*)",
"Bash(npm run dev:*)",
"Bash(npm run typecheck:*)",
"Bash(npx tsc:*)",
"Bash(bun run:*)",
"Bash(bun test:*)",
"Bash(node:*)",
"Bash(python3:*)",
"Bash(mkdir -p:*)",
"Bash(cp:*)",
"Bash(mv:*)",
"Bash(cat:*)",
"Bash(echo:*)",
"Bash(ls:*)",
"Bash(find:*)",
"Bash(grep:*)",
"Bash(wc:*)",
"Bash(which:*)",
"Bash(gh api:*)",
"Bash(gh repo:*)",
"Bash(xcodegen generate:*)",
"WebSearch",
"WebFetch(domain:developer.apple.com)",
"WebFetch(domain:developers.figma.com)",
"WebFetch(domain:github.com)",
"WebFetch(domain:raw.githubusercontent.com)",
"Read(**)",
"Edit(src/**)",
"Edit(Sources/**)",
"Edit(Tests/**)",
"Edit(tests/**)",
"Write(src/**)",
"Write(Sources/**)",
"Write(Tests/**)"
],
"ask": [
"Bash(git commit:*)",
"Bash(git push:*)",
"Bash(git merge:*)",
"Bash(git rebase:*)",
"Bash(npm install:*)",
"Bash(npm run build:*)",
"Bash(pod install:*)",
"Bash(brew install:*)",
"Edit(package.json)",
"Edit(Package.swift)",
"Edit(Podfile)",
"Edit(tsconfig.*)",
"Edit(vite.config.*)",
"Write(**)"
],
"deny": [
"Bash(rm -rf:*)",
"Bash(sudo:*)",
"Bash(curl * | *)",
"Bash(wget * | *)",
"Write(/Users/changyou/.ssh/*)",
"Edit(.env.production)",
"Edit(.env.prod)",
"Read(.env.production)"
]
}
}
把这份内容写入 ~/.claude/settings.json,对你机器上的所有项目立即生效。
哪些操作留在 ask,不是随意的
ask 里的每一条规则都有原因,不是懒得配置:
git commit / git push:提交和推送是有历史记录的操作,AI 生成的 commit message 质量参差不齐,push 之后改起来麻烦,留一个确认节点是值得的。
npm install / pod install:安装依赖会修改 lock 文件,引入外部包,需要人工感知,不应该静默发生。
npm run build:构建产物可能直接影响部署,尤其是 CI/CD 流程里,一个无意触发的 build 可能带来副作用。
配置文件(package.json、tsconfig.*、vite.config.*):这些文件的改动是全局性的,牵一发动全身,每次都看一眼没坏处。
deny 的几个设计细节
Edit(.env.production) 而不是 Edit(.env*)
很多人会把 .env* 全部 deny,然后发现 .env.local 也编辑不了了,开发寸步难行。只 deny 生产环境的配置文件,本地开发的 .env.local 和 .env.development 正常放行。
Write(/Users/changyou/.ssh/*) 用绝对路径
JSON 文件里的 ~ 不会被展开,~/.ssh/* 这条规则其实是无效的。用绝对路径才能真正生效。
Bash(curl * | *) 和 Bash(wget * | *)
拦截的是管道执行模式——把下载内容直接 pipe 给 shell 执行,这是最经典的供应链攻击手法。单纯的 curl 下载文件不受影响。
配置之后的实际变化
一个典型的功能迭代循环,配置前后的体验差别非常明显:
配置前:写代码 → 问你能不能保存 → 你确认 → 跑测试 → 问你能不能执行 → 你确认 → 检查 lint → 问你能不能运行 → 你确认。一个来回三次打断,Claude Code 退化成了一个需要人肉看管的工具。
配置后:Claude Code 独立完成"修改代码 → 保存 → 跑测试 → lint 检查"这整个循环,只在你要 commit 的时候停下来让你看一眼。你喝杯咖啡回来,任务已经完成了大半。
这才是 agentic 工具该有的样子。
一个要记住的判断原则
在决定一条规则放 allow 还是 ask 时,问自己一个问题:
这个操作如果 AI 执行出错,修复成本有多高?
- 读文件、搜索、查看目录:成本为零,无脑 allow
- 编辑源码:可以 git 回滚,allow 没问题
- 安装依赖、提交代码:有副作用,放 ask
- 删除文件、执行 sudo、修改生产配置:不可逆,放 deny

权限配置不是一次性工作。随着项目演进,你会遇到新的工具、新的目录结构,规则也要跟着调整。每次遇到"这个操作好像不该每次都问我",就是更新配置的信号。
把 AI 工具真正用好,从来不是"开箱即用"的事。
给它一个合理的边界,它才能在那个边界里跑得更快。
2026.03.25 17:06
沪 · 赵巷
📌 声明:本文由 AI 辅助完成