Claude Code 实战入门(九):settings.json、三层权限模型、env

settings.json 决定了 Claude 能动什么、在哪里、用谁的身份。三层(用户、项目、本地)、权限语法、改变行为的环境变量、以及那条第一次都会咬人的优先级规则。

如果说 Hooks 是你伸手进 Claude Code 的方式,settings.json 就是你告诉它能碰什么的地方。它也是那个会用优先级规则咬人的文件。

这一篇是缺失的那份参考手册。

三层

Claude Code 会按顺序读三份 settings.json:

  1. 用户级~/.claude/settings.json。对你这台机器上的所有项目生效。
  2. 项目级<repo>/.claude/settings.json。提交到 Git,对在这个仓库里干活的所有人生效。
  3. 本地级<repo>/.claude/settings.local.json。被 gitignore,是你针对这个仓库的私人覆盖。

合并规则:后面的层逐 key 覆盖前面的。但权限里的 allow 是叠加的,deny 是减法的——任何一层 deny 之后,没有任何其他层能再 allow 回来。这种不对称就是这套系统安全的关键。

实际后果:把组织策略放 ~/.claude/settings.json,把项目规则放 .claude/settings.json(提交的那份),把"我在这台机器上信任这一件事"的覆盖放 .claude/settings.local.json

permissions 块——语法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
{
  "permissions": {
    "allow": [
      "Read",
      "Edit(src/**)",
      "Bash(npm run *)",
      "Bash(git status)",
      "Bash(git diff *)",
      "WebFetch(domain:docs.anthropic.com)"
    ],
    "deny": [
      "Bash(rm -rf *)",
      "Bash(git push *)",
      "Read(.env)",
      "Read(**/credentials*)"
    ],
    "additionalDirectories": []
  }
}

括号里是按工具语义来的 glob 匹配:

  • Read(path-glob) — 文件路径模式。
  • Edit(path-glob) — 同上。
  • Bash(command-pattern) — 第一个 token 必须匹配。* 用得要小心:Bash(git *) 等于把 git push --force 也放过了。写得更具体。
  • WebFetch(domain:host) — 只匹配 host,不带路径。

裸写 ReadBash = 整个工具放过。除了在你完全信任的个人 ~/.claude/settings.json 里之外,这几乎总是太宽。

为什么 deny 永远赢

合并后的配置一旦在任何位置 deny 了某件事,没有任何其他位置能再 allow 回来。这就是你想要的那根杠杆。

例。仓库的 .claude/settings.json 写:

1
{ "permissions": { "deny": ["Bash(git push *)"] } }

队友在 .claude/settings.local.json"allow": ["Bash(git push origin main)"]push 不会被放行。 项目层的 deny 赢。这是对的,你应该靠它。

env——另外一半

env 块给每一次工具调用注入环境变量:

1
2
3
4
5
6
7
{
  "env": {
    "NODE_ENV": "development",
    "PYTHONPATH": "./src",
    "DEBUG": "false"
  }
}

两件事要知道:

  • 这些变量给 Bash 和任何继承环境的 hook 脚本用。它们不会进入模型的 prompt。所以放 *_API_KEY 是安全的。
  • 本地层覆盖项目层覆盖用户层。所以在 .claude/settings.local.json 里写 DEBUG=true,只对你打开日志,不会被提交到仓库。

hooks——在同一个文件里引用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Read|Grep",
        "hooks": [{ "type": "command", "command": "node ./hooks/block-env-read.js" }]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [{ "type": "command", "command": "node ./hooks/format.js" }]
      }
    ]
  }
}

matcher 是用竖线分隔的工具名。三层的 hooks 全部会被运行;hooks 没有"覆盖",深层加 hook 是叠加,不是替换。

一份真实仓库里的 settings.json

下面是我自己一个项目的项目级配置,做了少量打码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
{
  "permissions": {
    "allow": [
      "Read",
      "Edit(src/**)",
      "Edit(tests/**)",
      "Edit(docs/**)",
      "Bash(npm run *)",
      "Bash(git status)",
      "Bash(git diff *)",
      "Bash(git log *)",
      "Bash(git add *)",
      "Bash(git commit *)",
      "WebFetch(domain:docs.anthropic.com)",
      "WebFetch(domain:nodejs.org)"
    ],
    "deny": [
      "Bash(rm -rf *)",
      "Bash(git push *)",
      "Bash(git reset --hard *)",
      "Edit(.github/workflows/**)",
      "Read(.env)",
      "Read(.env.*)",
      "Read(**/credentials*)"
    ]
  },
  "env": {
    "NODE_ENV": "development",
    "CI": "false"
  },
  "hooks": {
    "PreToolUse": [
      { "matcher": "Read|Grep", "hooks": [{ "type": "command", "command": "node ./hooks/block-env-read.js" }] },
      { "matcher": "Bash",      "hooks": [{ "type": "command", "command": "node ./hooks/bash-blacklist.js" }] }
    ],
    "PostToolUse": [
      { "matcher": "Edit|Write", "hooks": [{ "type": "command", "command": "node ./hooks/format.js" }] }
    ]
  }
}

三件事值得注意:

  1. Bash 的 allow 列表收了只读和可逆的 git 命令,但永远没有 pushreset --hardrebase -i。Push 是人来按的动作。
  2. Edit(.github/workflows/**) 被 deny。CI 配置改动需要 review,不能跟着普通 commit 溜走。
  3. Hooks 给 deny 列表上双保险。万一 deny 规则有 typo,hook 仍然会拦下危险调用。

优先级——按顺序的清单

行为不符合预期时按这个顺序查:

  1. 是否在任何 deny 里?→ 拦截,不管 allow 怎么写。
  2. 是否在任何 allow 里?→ 放行。
  3. 否则 → Claude 做之前会问你。

想知道哪条规则赢了,加 --debug 跑一遍,读权限解析日志。它会告诉你哪一文件、哪一行给出了判决。

收尾

settings.json 是这个项目里 Claude 行为的宪法。Deny 写得短而狠,allow 写得具体,hooks 当第二道防线。把分层和优先级钉进脑子里,配新仓库九十秒就够。在那之前规则会让你觉得任性;它们不是。

翻完了?

去 GitHub 关注一下,新一篇通常隔一周就到。

GitHub