Featured image of post AI 编程 CLI 的权限怎么配:Claude Code、Codex CLI 与 OpenCode 对比

AI 编程 CLI 的权限怎么配:Claude Code、Codex CLI 与 OpenCode 对比

聚焦 Claude Code、Codex CLI 与 OpenCode 的权限控制方式,对比配置文件层级、规则语法、匹配逻辑与多仓库实践,帮助快速设计安全边界。

-- 次浏览
-- 条评论

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 CodeCodex CLIOpenCode
权限配置文件settings.jsonopencode.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__toolMCP 工具服务名__工具名

路径写法规则:

写法含义
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
bashShell 命令ask
webfetchHTTP 请求allow
task任务执行allow
lsp语言服务器allow
skill技能调用allow
external_directory外部目录访问ask
doom_loop循环执行ask

特殊默认行为:即使 readallow.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/**)"                  来自项目
  ]

标量字段(高优先级完全覆盖低优先级):
  modeltheme 

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 CodeCodex CLIOpenCode
配置文件settings.jsonopencode.json
层级数量4层(managed/user/project/local)多层(remote/global/project/inline)
目录向上遍历❌ 固定路径✅ 向上遍历查找(停在 git root)
企业管控层✅ managed 不可覆盖⚠️ 远程配置(需 HTTPS)
跨项目共享~/.claude/settings.json~/.config/opencode/opencode.json

权限规则对比

特性Claude CodeCodex CLIOpenCode
细粒度 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 左右公开资料与实测整理,工具迭代很快,真正上线前仍然建议再对照一次官方文档。

参考资料