别让 Claude Code 一直问你"能不能执行":权限配置完全指南

用了 Claude Code 一段时间,有件事让我很头疼。

每次让它帮我写完一段代码,它要问我一句"能不能保存文件"。跑个测试,又问一句。创建个目录,再问一句。本来是来解放双手的,结果变成了另一种形式的"人肉确认机器"。

直到我彻底搞懂了它的权限配置系统,这个问题才真正解决。


为什么 Claude Code 会不断打断你

Claude Code 的设计哲学是谨慎优先。它默认对几乎所有文件操作、终端命令都会暂停下来问你一句,因为 AI 执行出错的代价,可能比慢一点高得多。

这个设计是对的。

但问题在于,"谨慎"和"高频打断"之间有巨大的差距。git status 这种只读命令,swift build 这种本地构建,根本不需要每次确认。真正需要谨慎的,是 git pushnpm 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.jsontsconfig.*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 辅助完成

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容