AI 编程 CLI 的权限怎么配:Claude Code、Codex CLI 与 OpenCode 对比
这篇文章只聚焦一个问题:三款 AI 编程 CLI 分别怎样控制权限,规则写在哪里,真正生效时又按什么顺序匹配。
如果还没决定用哪一款工具,建议先看总览文,先把选型框架建立起来,再回来研究权限细节。
总览文入口:AI 编程 CLI 工具怎么选:Claude Code、Codex CLI 与 OpenCode 对比
写在前面
如果把指令文件比作 AI 的“项目说明书”,那权限配置更像机房门禁。说明书决定它应该怎么做,权限系统决定它到底能做什么。
三款工具的差别主要集中在三个地方:
- Claude Code 侧重“配置层级 + 白名单规则”,适合需要严格边界的场景。
- Codex CLI 侧重“审批模式 + OS 沙箱”,概念最少,上手最快。
- OpenCode 侧重“工具级权限 + 命令匹配”,灵活度高,但也更依赖使用者自己设计规则。
如果你还在研究项目说明文件怎么加载、怎么合并,可以配合下面这篇专题一起看:
AI 编程 CLI 的指令文件怎么生效:CLAUDE.md、AGENTS.md 与 OpenCode 对比
三款工具的权限机制概览
| 维度 | Claude Code | Codex CLI | OpenCode |
|---|
| 权限配置文件 | settings.json | 无 | opencode.json |
| 控制粒度 | 细粒度(工具 + 路径模式) | 粗粒度(三种模式) | 细粒度(工具 + 命令模式) |
| 沙箱机制 | 规则白名单 | macOS Seatbelt / Docker | 规则白名单 |
| 企业管控 | ✅ managed 层不可覆盖 | ❌ | ⚠️ 远程配置 |
配置文件层级
Claude Code — settings.json(4 层级,固定路径,不遍历目录)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| 优先级从高到低:
① 系统托管(不可被任何层级覆盖)
macOS: /Library/Application Support/ClaudeCode/managed-settings.json
Linux: /etc/claude-code/managed-settings.json
Windows: C:\Program Files\ClaudeCode\managed-settings.json
HKLM\SOFTWARE\Policies\ClaudeCode(注册表)
② 命令行参数(临时会话级覆盖)
③ 本地项目(个人私有,git 忽略)
<repo>/.claude/settings.local.json
④ 共享项目(团队共享,git 追踪)
<repo>/.claude/settings.json
⑤ 用户全局(最低优先级)
~/.claude/settings.json
|
与 CLAUDE.md 加载行为的核心差异:
1
2
| CLAUDE.md → 目录向上遍历,沿途所有文件全部加载(越过 git root 继续)
settings.json → 固定路径,不做任何目录遍历
|
关键限制:~/projects/.claude/settings.json 这样的路径即使存在也不会被加载,跨项目共享权限只能放入 ~/.claude/settings.json。
Codex CLI — 无配置文件
1
2
3
4
5
6
7
8
9
10
11
| 权限控制完全依赖启动参数,三种模式:
--approval-mode suggest 所有操作需用户确认(默认)
--approval-mode auto-edit 文件编辑自动批准,shell 命令需确认
--approval-mode full-auto 全自动执行(依赖 OS 沙箱隔离)
沙箱机制:
macOS:Seatbelt(系统调用级别隔离)
Linux:Docker 容器隔离
full-auto 模式:网络访问被完全禁止,文件系统受 OS 限制
|
OpenCode — opencode.json(多层级,支持目录遍历)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| 加载顺序(优先级从低到高):
① 远程组织配置(最低)
.well-known/opencode(通过 HTTP 拉取,组织级默认值)
② 用户全局配置
~/.config/opencode/opencode.json
③ 环境变量指定路径
$OPENCODE_CONFIG 指向的文件
④ 项目配置(从当前目录向上遍历查找,停在 git root)
./opencode.json
⑤ .opencode 目录(agents/, commands/ 等子目录)
⑥ 内联配置(最高)
$OPENCODE_CONFIG_CONTENT 环境变量内容
|
OpenCode 特点:opencode.json 支持目录向上遍历查找(不同于 Claude Code 的固定路径),且多层级配置深度合并而非替换。
权限规则语法
Claude Code
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
| // .claude/settings.json
{
"permissions": {
"allow": [
"Bash(npm run *)", // Bash 命令,支持通配符
"Bash(git commit *)",
"Read(./src/**)", // 文件读取,gitignore 风格
"Read(~/data/work/**)", // 波浪号路径(指定目录免确认)
"Edit(./src/**/*.java)", // 文件编辑
"WebFetch(domain:github.com)", // 域名匹配
"Glob(**/*.ts)", // 文件搜索
"Grep(./src/**)" // 内容搜索
],
"deny": [
"Bash(rm -rf *)",
"Bash(curl *)",
"Read(./.env*)", // 拒绝读取环境变量文件
"Read(./secrets/**)"
],
"ask": [
"Bash(git push *)", // 敏感操作需二次确认
"Bash(docker *)",
"Bash(kubectl *)"
]
}
}
|
匹配规则:deny → ask → allow,首个匹配生效,后续规则忽略。
支持的工具名:
| 工具 | 说明 | 路径模式 |
|---|
Bash(pattern) | Shell 命令执行 | 命令通配符,如 npm run * |
Read(pattern) | 文件读取 | gitignore 风格,如 ./src/** |
Edit(pattern) | 文件编辑 | gitignore 风格 |
Write(pattern) | 文件写入 | gitignore 风格 |
Glob(pattern) | 文件名搜索 | glob 模式 |
Grep(pattern) | 内容搜索 | 目录路径 |
WebFetch(domain:x) | HTTP 请求 | 域名匹配 |
Agent(name) | 子 Agent 调用 | Agent 名称 |
mcp__srv__tool | MCP 工具 | 服务名__工具名 |
路径写法规则:
| 写法 | 含义 |
|---|
Read(./src/**) | 项目内相对路径 |
Read(~/data/work/**) | 家目录下的路径 |
Read(//absolute/path/**) | 双斜杠开头表示绝对路径 |
Read(./.env*) | 精确匹配特定文件 |
OpenCode
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| // opencode.json
{
"permission": {
// 工具级别全局设置
"read": "allow",
"edit": "allow",
"glob": "allow",
"grep": "allow",
"list": "allow",
"webfetch": "ask",
"lsp": "allow",
// bash 细粒度规则(最后匹配生效)
"bash": {
"*": "ask", // 默认所有命令需确认
"git *": "allow", // git 命令放行
"npm run *": "allow", // npm 命令放行
"rm *": "deny", // 拒绝 rm
"curl *": "deny" // 拒绝 curl
}
}
}
|
匹配规则:最后匹配生效(Last Match Wins),与 Claude Code 相反。
支持的工具名:
| 工具 | 说明 | 默认值 |
|---|
read | 文件读取 | allow |
edit | 文件编辑 | allow |
glob | 文件搜索 | allow |
grep | 内容搜索 | allow |
list | 目录列表 | allow |
bash | Shell 命令 | ask |
webfetch | HTTP 请求 | allow |
task | 任务执行 | allow |
lsp | 语言服务器 | allow |
skill | 技能调用 | allow |
external_directory | 外部目录访问 | ask |
doom_loop | 循环执行 | ask |
特殊默认行为:即使 read 为 allow,.env 文件默认仍为 deny,需显式解除。
Codex CLI
1
2
3
4
| # 无配置文件,仅启动参数
codex --approval-mode suggest # 全部询问(默认)
codex --approval-mode auto-edit # 文件编辑自动放行
codex --approval-mode full-auto # 沙箱内全自动
|
合并策略
Claude Code — 数组合并 + 标量覆盖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| 数组类字段(跨层级合并,去重):
permissions.allow / deny / ask
示例:
managed-settings.json: allow: ["Bash(//opt/company-tools/*)"]
~/.claude/settings.json: allow: ["Bash(npm run *)", "Bash(mvn *)"]
.claude/settings.json: allow: ["Bash(git *)", "Read(./src/**)"]
最终生效:
allow: [
"Bash(//opt/company-tools/*)", ← 来自 managed
"Bash(npm run *)", ← 来自用户全局
"Bash(mvn *)", ← 来自用户全局
"Bash(git *)", ← 来自项目
"Read(./src/**)" ← 来自项目
]
标量字段(高优先级完全覆盖低优先级):
model、theme 等
deny 的特殊地位:
任何层级的 deny 均生效,低层级无法解除
managed 层设置的 deny 不可被任何层级覆盖
|
OpenCode — 深度合并 + 最后匹配
规则一:多层级配置文件深度合并
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
| ~/.config/opencode/opencode.json(用户全局):
{
"permission": {
"read": "allow",
"edit": "allow",
"bash": {
"*": "ask",
"git *": "allow"
}
}
}
./opencode.json(项目级):
{
"permission": {
"webfetch": "deny", // 项目级新增字段
"bash": {
"npm run *": "allow" // 项目级追加规则
}
}
}
合并结果:
{
"permission": {
"read": "allow", // 来自全局
"edit": "allow", // 来自全局
"webfetch": "deny", // 来自项目(新增)
"bash": {
"*": "ask", // 来自全局
"git *": "allow", // 来自全局
"npm run *": "allow" // 来自项目(追加)
}
}
}
|
规则二:bash 规则内部按"最后匹配"生效
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| 合并后的 bash 规则:
"*": "ask"
"git *": "allow"
"npm run *": "allow"
执行 "git commit -m fix" 时:
匹配 "*" → ask
匹配 "git *" → allow ← 最后匹配,最终生效 ✅
执行 "curl http://..." 时:
匹配 "*" → ask ← 唯一匹配,最终生效 ✅
执行 "rm -rf /tmp" 时:
匹配 "*" → ask ← 唯一匹配,最终生效 ✅
|
规则三:Agent 级别直接覆盖全局(不合并)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| {
"permission": {
"bash": { "*": "ask", "git *": "allow" } // 全局权限
},
"agent": {
"reviewer": {
"permission": {
"read": "allow",
"bash": "deny", // 直接覆盖,全局的 git * allow 被完全忽略
"edit": "deny"
}
}
}
}
|
1
2
3
4
5
6
7
| reviewer agent 最终权限:
read: allow ← agent 定义
bash: deny ← agent 定义(全局 git * allow 失效)
edit: deny ← agent 定义
默认 agent 最终权限:
bash: { "*": "ask", "git *": "allow" } ← 使用全局规则
|
与 Claude Code 的关键区别:Claude Code 的 deny 一旦设置不可逆;OpenCode 的 agent 级别可以完全覆盖全局规则,包括把全局的 deny 改回 allow。
多仓库场景实践
Claude Code 配置示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| ~/projects/
├── CLAUDE.md ✅ 指令文件,目录遍历自动加载
├── .claude/settings.json ❌ 不会被加载(不在固定路径)
│
├── order-service/
│ ├── CLAUDE.md ✅ 指令文件,自动加载
│ └── .claude/
│ ├── settings.json ✅ 项目级权限(团队共享)
│ └── settings.local.json ✅ 本地个人权限(git 忽略)
│
└── notify-service/
├── CLAUDE.md ✅ 指令文件,自动加载
└── .claude/
└── settings.json ✅ 项目级权限(团队共享)
|
~/.claude/settings.json(跨所有项目生效):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| {
"permissions": {
"allow": [
"Bash(git *)",
"Bash(mvn *)",
"Bash(npm run *)",
"Read(~/data/work/**)",
"Read(~/.claude/**)"
],
"deny": [
"Bash(rm -rf *)",
"Read(./.env*)",
"Read(./secrets/**)"
],
"ask": [
"Bash(git push *)",
"Bash(kubectl *)",
"Bash(docker *)"
]
}
}
|
~/projects/order-service/.claude/settings.json(仅 order-service 生效):
1
2
3
4
5
6
7
8
9
10
| {
"permissions": {
"allow": [
"Bash(java *)",
"Bash(mvn spring-boot:run)",
"Read(./src/**)",
"Edit(./src/**)"
]
}
}
|
~/projects/order-service/.claude/settings.local.json(个人本地,不提交 git):
1
2
3
4
5
6
7
8
| {
"permissions": {
"allow": [
"Bash(ssh *)",
"Read(~/.ssh/config)"
]
}
}
|
合并结果:三个文件的 permissions 数组跨层级合并去重,最终生效的是三者的并集。
OpenCode 配置示例
~/.config/opencode/opencode.json(跨所有项目生效):
1
2
3
4
5
6
7
8
9
10
11
12
13
| {
"permission": {
"read": "allow",
"edit": "allow",
"bash": {
"*": "ask",
"git *": "allow",
"mvn *": "allow",
"rm -rf *": "deny",
"curl *": "deny"
}
}
}
|
~/projects/order-service/opencode.json(仅 order-service 生效,与全局深度合并):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| {
"permission": {
"bash": {
"java *": "allow",
"mvn spring-boot:run": "allow"
}
},
"agent": {
"reviewer": {
"permission": {
"read": "allow",
"edit": "deny",
"bash": "deny"
}
}
}
}
|
横向对比总表
配置文件对比
| 特性 | Claude Code | Codex CLI | OpenCode |
|---|
| 配置文件 | settings.json | 无 | opencode.json |
| 层级数量 | 4层(managed/user/project/local) | 无 | 多层(remote/global/project/inline) |
| 目录向上遍历 | ❌ 固定路径 | ❌ | ✅ 向上遍历查找(停在 git root) |
| 企业管控层 | ✅ managed 不可覆盖 | ❌ | ⚠️ 远程配置(需 HTTPS) |
| 跨项目共享 | ~/.claude/settings.json | 无 | ~/.config/opencode/opencode.json |
权限规则对比
| 特性 | Claude Code | Codex CLI | OpenCode |
|---|
| 细粒度 allow/deny/ask | ✅ | ❌ | ✅ |
| 匹配规则逻辑 | 首个匹配(deny→ask→allow) | 无 | 最后匹配 |
| 数组跨层合并 | ✅ permissions 数组跨层合并去重 | ❌ | ✅ 深度合并 |
| deny 可逆性 | ❌ 任意层级 deny 不可被低层解除 | ❌ | ✅ agent 级可覆盖全局 |
| Agent 级别权限 | ❌ | ❌ | ✅ 可覆盖全局 |
| .env 文件保护 | ⚠️ 需手动 deny | ❌ | ✅ 默认 deny |
规则匹配逻辑对比
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| Claude Code(首个匹配):
规则检查顺序:deny → ask → allow
第一个匹配的规则立即生效,后续规则忽略
陷阱示例:
deny: ["Bash(rm *)"]
allow: ["Bash(rm -rf /tmp/*)"] ← 永远不会生效(已被 deny 首先匹配)
正确写法:把宽泛的 deny 放后面,具体的 allow 放前面
allow: ["Bash(rm -rf /tmp/*)"] ← 先匹配,放行 /tmp 下的删除
deny: ["Bash(rm *)"] ← 再匹配其他 rm 命令
OpenCode(最后匹配):
越靠后的规则优先级越高,适合从宽泛默认逐步精细化
示例:
"bash": {
"*": "ask", // 默认询问
"rm *": "deny", // 拒绝 rm
"rm /tmp/*": "allow" // 最后匹配:/tmp 下 rm 允许 ✅
}
|
总结
如果你的首要目标是把风险压到最低,Claude Code 的层级和规则模型更容易建立清晰边界。
如果你更看重简单直接,不想维护额外配置,Codex CLI 的审批模式更适合快速上手。
如果你需要更自由的命令匹配和多 Agent 权限设计,OpenCode 的可塑性会更强,但也更考验配置习惯。
文中的规则和行为基于 2026-03-18 左右公开资料与实测整理,工具迭代很快,真正上线前仍然建议再对照一次官方文档。
参考资料: