Codex CLI 的 config.toml 比你想象的能玩:六层优先级、信任沙箱、还有一堆官方默默打开的好东西

斜杠命令是用来在会话里临时切换状态的------切个模型、压缩一下上下文、调调审批宽严。但真正决定 Codex 每次启动时长什么样 的,是它读的那个 config.toml:模型、审批策略、沙箱权限、MCP 服务器、自定义模型提供商、通知、遥测,全在这一个文件里(外加它的几个邻居)。

这篇按"从位置到优先级,再到那些你大概率没注意到的细节"递进着讲。目标是看完之后你能自信地打开自己的 ~/.codex/config.toml 改任何键,并且知道改完会发生什么

一、文件长在哪,谁说了算

先认两个最常用的位置------

用户级~/.codex/config.toml。这个目录的根路径由 CODEX_HOME 环境变量决定,默认就是 ~/.codex。同一个目录里你还会看到 auth.json(你登录的凭证文件,如果你用的不是系统钥匙串)、history.jsonl(会话历史记录)、日志和缓存。

项目级 :你仓库里的 .codex/config.toml。Codex 从项目根一路往下走到当前工作目录 ,沿途遇到的每一个 .codex/config.toml 都加载。如果多个文件设了同一个键,离 cwd 最近的那个赢

但这两个文件不是 Codex 唯一会读的配置源。完整的优先级链一共六层,从高到低:

  1. CLI 命令行 flag 和 -c / --config 即席覆盖
  2. Profile 值(来自 --profile <name>
  3. 项目级 .codex/config.toml(root → cwd,closest wins,仅信任的项目
  4. 用户级 ~/.codex/config.toml
  5. 系统级配置(如果存在):Unix 上是 /etc/codex/config.toml
  6. 内置默认值

举个具体例子让你感受一下:你在用户级 config.toml 里设了 model = "gpt-5.5",进了某个仓库,仓库的 .codex/config.toml 把它覆盖成 gpt-5-pro,然后启动时你又加了 --model gpt-4.1------最后实际生效的是 gpt-4.1。CLI flag 优先级最高,盖过 profile,盖过项目层,盖过用户层。

实操原则:用户级和系统级放"几乎所有项目都通用的默认"(比如说话风格、通知、文件打开器),项目级只放"这个仓库特殊"的东西(比如这个项目要用什么模型、网络要不要开),profile 用来切场景(深度审查 vs 快速干活)。这样后期排错的时候你脑子里有清晰的层级。

实际行为和你配置的对不上?跑 /debug-config------它会按这个顺序把所有层一次性打出来,排错不用瞎猜。


二、信任模型:一条很多人忽视的安全护栏

项目被标记为 untrusted 时,Codex 会跳过整个项目级 .codex/ ------包括 config.toml、本地 hooks、本地 rules 全都不加载。用户级和系统级照常加载。

信任状态记在用户级 config.toml(不在项目里------项目自己说自己可信没意义):

toml 复制代码
# 写在 ~/.codex/config.toml 里
[projects."/absolute/path/to/project"]
trust_level = "trusted"  # 或 "untrusted"

为什么这个细节重要?想象一下:有人往一个开源仓库塞个 .codex/config.toml,把审批策略改成 never、沙箱开 danger-full-access。如果你 git clone 下来跑 Codex 的瞬间项目层就无脑生效,等于把钥匙交给陌生人。不信任 = 不加载这条规则,等于把这种攻击面直接关掉。

顺带提一句:Codex 怎么判断一个目录是不是项目根?靠 project_root_markers默认是 [".git"] ------也就是说一个目录里有 .git 文件夹就算根。你可以加上 .hg(Mercurial)、.sl(Sapling),或者直接把它设成 [] 让 Codex 不再向上找父目录、就把当前 cwd 当根。


三、最常调的那几个键

下面五个键覆盖了绝大多数日常配置场景,先讲清楚它们在干什么。

model 选模型。官方示例里给的就是 "gpt-5.5"。还有个 review_model,是单独给 /review 命令用的覆盖------你可以让日常对话用便宜模型,让代码审查走更强的 reasoning 模型,留空就跟当前会话同一个。

approval_policy 控制 Codex 什么时候停下来问你。四种值:

  • untrusted------只有公认安全的只读命令(像 lscat)才自动跑,别的全都问你
  • on-request------模型自己决定何时问(默认行为,最日常)
  • never------不问,直接干(脚本/CI 环境用,本地慎用)
  • granular = { ... }------按提示类别分别放行

最后这种"细粒度"模式值得单独讲一下,因为里面 5 个开关名字看着抽象:

toml 复制代码
approval_policy = { granular = {
  sandbox_approval = true,      # 要逃出沙箱时,让 Codex 来问你
  rules = true,                 # 命中 .rules 里写的 prompt 规则时问
  mcp_elicitations = true,      # MCP 工具反过来要你输入信息时问
  request_permissions = false,  # 工具要你授权扩大权限时,自动拒
  skill_approval = false        # 跑 Skill 脚本要审批时,自动拒
} }

简单说:true 表示"会弹窗问你",false 表示"直接拒掉,连问都不问"。这个机制让你能保留交互式审批做大事,同时让一些噪音类提示自动 fail closed

sandbox_mode 是文件系统/网络访问的隔离等级,三档:read-only(默认)、workspace-writedanger-full-access等于关沙箱,慎用)。

web_search 默认是 "cached"------它用的是 OpenAI 维护的网页索引缓存,返回的是预索引结果而不是实时去抓页面。这么做的核心理由:实时网页里随便一段文字都可能是 prompt injection,缓存等于在你和恶意页面之间多了一层过滤。

"live" 会去实时抓页面,"disabled" 直接关掉。一个不少人不知道的细节:--yolo 或者其他完全访问沙箱设置时,Codex 知道你已经选了"放飞"的姿态,会自动把 web_search 切到 "live"

personality 设说话风格,三种:friendlypragmaticnone。运行时还能用 /personality 临时改。


四、审批和沙箱:两个独立维度,别搞混

新手最容易把这俩混成一回事,所以单独拎出来讲。

审批策略 控制的是"问不问你"。沙箱模式 控制的是"就算不问你,最多能干啥"。两者独立配置、共同生效 ------你可以一边设 never(永远不问),一边设 read-only(无论如何只能读)。这种组合在 CI 里很常见。

workspace-write 模式下有几个反直觉的地方:

toml 复制代码
[sandbox_workspace_write]
writable_roots = ["/Users/YOU/.pyenv/shims"]
network_access = false          # 网络默认是关的
exclude_tmpdir_env_var = false  # 允许 $TMPDIR
exclude_slash_tmp = false       # 允许 /tmp

网络默认关闭 ,要 pip install 或者 npm i 都得显式打开 network_access = true。这个默认很重要------它意味着即使模型脑抽了想 curl 个奇怪 URL,也走不通。

第二个反直觉点:即使在 workspace-write 下,.git/.codex/ 在某些环境里依然是只读的 。这是有意为之------.git/ 是你的所有提交历史,.codex/ 是你的本地配置和 hooks,这俩被改坏的代价远大于源代码被改坏 。代价是 git commit 这种命令有时候会要求审批让它在沙箱外跑。如果你想让 Codex 完全跳过某些命令(比如禁止 git commit 在沙箱外执行),用 rules 来表达。

最后还有个键叫 approvals_reviewer,决定当审批弹出来的时候由谁来按 Yes/Nouser(默认,你自己来)、auto_review(走 reviewer subagent 自动审)。这个键只换"按按钮的人",不动沙箱的边界------也就是说就算改成自动审,沙箱该挡的还挡。


五、Profiles:多套配置切着用

Profile 是一组命名的配置预设,让你在 CLI 里一行切换。先泼两盆冷水:Profiles 是 experimental 的,将来可能改 ;而且目前 IDE 扩展不支持 profile,只在 CLI 里能用。

toml 复制代码
model = "gpt-5.4"
approval_policy = "on-request"

[profiles.deep-review]
model = "gpt-5-pro"
model_reasoning_effort = "high"
approval_policy = "never"

[profiles.lightweight]
model = "gpt-4.1"
approval_policy = "untrusted"

启动时加 --profile deep-review 就用对应那套;不加就用顶层默认。要把某个 profile 设成默认(不加 --profile 时也用它),在顶层加:

ini 复制代码
profile = "deep-review"

我个人喜欢的用法是:顶层放"日常",profile 放"特殊场景"------比如一个 lightweight 用来跑批量小任务、一个 deep-review 用来代码审查。


六、一次性 CLI 覆盖:不想改文件就改一次

toml 复制代码
# 专用 flag 优先用
codex --model gpt-5.4

# 通用 key/value
codex --config model='"gpt-5.4"'
codex --config sandbox_workspace_write.network_access=true
codex --config 'shell_environment_policy.include_only=["PATH","HOME"]'

三个一定要知道的细节------

值是 TOML 格式,不是 JSON 。这意味着字符串要带双引号('"gpt-5.4"' 这种鬼样子是因为 shell 一层、TOML 一层,两层引号嵌套),但布尔值 true、数字 42、数组 [1,2,3] 不用。TOML 里 true 不带引号、字符串带引号------记住这条就够了。

点号语法 支持嵌套键:mcp_servers.context7.enabled=false 就能精准关掉某个 MCP 服务器,不用把整个 mcp_servers 表写一遍。

值解析不了 TOML 时会被当字符串------这是个静默兜底,意思是你写错了它不一定报错,可能默默把你的值当成普通字符串处理。所以调试出怪事的时候,先怀疑自己引号有没有写对。


七、Feature flags:默认就开了一堆好东西

[features] 表是开关集中地。很多稳定特性默认就开了 ,意味着你不需要做任何配置就能用上:shell_toolshell_snapshot(缓存 shell 环境加速重复命令)、unified_exec(PTY-backed 的 exec,Windows 之外默认开 )、multi_agent(subagent 协作)、personalityfast_modecodex_hooks,全是 默认 true

默认关着、值得手动打开的也有几个:

undo 默认 false 。开了之后 Codex 会每一轮在 git 里偷偷打一个隐形快照(官方叫 "git ghost snapshot",本质就是个不污染你 commit 历史的临时备份),你可以一键撤销那一轮的所有改动。代价就是磁盘多写一点、git object 多一些。我觉得绝大多数人都该开这个。

memories 默认 false 。开启后 Codex 会跨会话记住你之前讨论过的东西。配套的 [memories] 表里有一堆参数可调:max_raw_memories_for_consolidation 默认 256(上限 4096)、max_unused_days 默认 30(范围 0-365)、max_rollout_age_days 默认 30(范围 0-90)------意思是 Codex 不会无限囤积记忆,30 天没用的会自动从候选池里淘汰。

apps 是 experimental,开了之后能用 ChatGPT Apps/connectors。

至于 web_searchweb_search_cachedweb_search_request 这三个旧 boolean 开关------已经废弃了 ,全部改用顶层的 web_search 字符串。如果你的旧配置里还在用这些 boolean,今天就该迁。


八、MCP servers:把外部工具接进来

MCP(Model Context Protocol)是让 Codex 调用外部工具的协议------文档检索、Issue 跟踪、监控查询,凡是你想让 Codex 能"读到外部数据"或"对外部系统下命令"的,都通过 MCP 服务器暴露给它。

配置在 [mcp_servers.<id>] 下面,两种传输方式根据工具是本地的还是远程的来选:

stdio :在你机器上起一个本地子进程,Codex 通过标准输入输出和它对话。适合本地工具(命令行扫码器、本地数据库代理这类):

toml 复制代码
[mcp_servers.docs]
command = "docs-server"
args = ["--port", "4000"]
env = { "API_KEY" = "value" }
required = true                  # 启动时这个 server 起不来直接失败
startup_timeout_sec = 10.0       # 默认 10 秒
tool_timeout_sec = 60.0          # 默认 60 秒
enabled_tools = ["search"]       # 白名单
disabled_tools = ["slow-tool"]   # 黑名单(在白名单之后应用)

Streamable HTTP :连一个远端服务。适合 SaaS 类的工具(GitHub、Linear 那种):

toml 复制代码
[mcp_servers.github]
url = "https://github-mcp.example.com/mcp"
bearer_token_env_var = "GITHUB_TOKEN"
http_headers = { "X-Example" = "value" }
env_http_headers = { "X-Auth" = "AUTH_ENV" }

两个细节值得记:

required = true 之后这个 server 启动失败会让整个会话起不来------对关键依赖(比如你的内部知识库)很有用,免得 Codex 在没有它的情况下"将就着"跑。

disabled_toolsenabled_tools 之后应用的------意思是你可以"白名单先放一批,再单独黑掉某个"。这个组合很实用:开放整个 MCP server 但屏蔽掉那个又慢又会扣费的工具。


九、自定义模型提供商:把 Codex 接到别的地方

模型提供商定义在 [model_providers.<id>]保留 ID openaiollamalmstudio 不能覆盖 ------要改内置 OpenAI 的基础 URL(比如走数据驻留区域),用顶层的 openai_base_url,别另起一个 [model_providers.openai],会被无视。

最常见的几种场景------

LLM 代理(公司内部的 OpenAI 转发层):

toml 复制代码
model_provider = "proxy"

[model_providers.proxy]
name = "OpenAI using LLM proxy"
base_url = "http://proxy.example.com"
env_key = "OPENAI_API_KEY"

Azure OpenAI :要带 query_params 里的 api-version,wire_api 是 responses

toml 复制代码
[model_providers.azure]
base_url = "https://YOUR_PROJECT.openai.azure.com/openai"
env_key = "AZURE_OPENAI_API_KEY"
query_params = { api-version = "2025-04-01-preview" }
wire_api = "responses"
request_max_retries = 4
stream_max_retries = 10
stream_idle_timeout_ms = 300000

Command-backed auth ------这是企业里很常见的场景:你公司有一个内部 SSO/OAuth 服务,token 不是放在环境变量里的固定值,而是要调用一个本地命令现拿(比如 AWS STS、GCP gcloud auth、或者你公司自己写的 token broker):

toml 复制代码
[model_providers.proxy.auth]
command = "/usr/local/bin/fetch-codex-token"
args = ["--audience", "codex"]
timeout_ms = 5000
refresh_interval_ms = 300000

注意几个约束:auth 命令不会收到 stdin ,它必须把 token 打到 stdout ,Codex 会去掉首尾空白;空 token 算错误。refresh_interval_ms 默认 300000(5 分钟主动刷新一次);设 0 表示只在认证失败重试时才刷新 。这个 [auth] 子表不能和 env_keyexperimental_bearer_tokenrequires_openai_auth 混用------选了一种就锁定一种。

OSS 模式(本地模型):用 --oss 启动,默认走 oss_provider

toml 复制代码
oss_provider = "ollama"  # 或 "lmstudio"

十、Shell 环境策略:别让你的 API key 流到子进程

要先讲清楚为什么这是个问题 :当 Codex 跑一个 shell 命令(比如 npm install),那个子进程默认会继承 Codex 自己的所有环境变量 ------包括你的 OPENAI_API_KEY、AWS 凭证、GitHub token 等等。这意味着你跑的某个 npm 包如果里面藏了恶意脚本读 process.env,所有秘钥就一起泄了。

shell_environment_policy 就是用来卡这个口子的:

toml 复制代码
[shell_environment_policy]
inherit = "core"                # all | core | none
ignore_default_excludes = false # 保留 KEY/SECRET/TOKEN 自动过滤
exclude = ["AWS_*", "AZURE_*"]  # 大小写不敏感的 glob
include_only = ["PATH", "HOME"] # 白名单
set = { MY_FLAG = "1" }         # 直接覆写

inherit 是"基线":all 全继承(不安全,等于没设),core 继承基础几个(PATH 这种),none 啥都不继承。

ignore_default_excludes = false(默认行为)的时候,所有变量名包含 KEY/SECRET/TOKEN 的都会先被自动过滤掉 (大小写不敏感),然后才轮到你写的 include/exclude 规则跑。这是个救命的兜底------但最佳实践还是 inherit = "none" + set 显式列出来你想传什么,别依赖默认过滤。


十一、其余几个值得知道的小开关

通知有两套机制notify 是外部命令(适合接桌面通知、CI webhook),它会被传一个 JSON 参数,里面有事件类型、thread id、最近一条助手消息等等;tui.notifications 是 TUI 自带的,能按事件类型过滤(比如只在 ["agent-turn-complete", "approval-requested"] 时响)。

tui.notification_method 控制实际机制:auto(默认,优先发 OSC 9,回退 BEL \x07 )、osc9bel。OSC 9 是某些终端能识别的转义序列,触发系统级桌面通知;BEL 就是老派的"叮"一声。

点击跳转file_opener 决定 Codex 输出里的文件引用怎么变成可点击链接:vscode(默认)、cursorwindsurfvscode-insidersnone。引用 /path/to/main.py:42 会被改写成 vscode://file/...:42,编辑器接住就直接跳到那行。

历史持久化 :默认会把会话存到 history.jsonl。要关:

toml 复制代码
[history]
persistence = "none"
max_bytes = 104857600  # 100 MiB,超了之后丢最老的

遥测分两块看 :OTel(默认 exporter = "none",要主动开才会往外发数据),和 analytics(默认开,不含 PII 的匿名使用统计)。后者要关:

toml 复制代码
[analytics]
enabled = false

/feedback 也能整体禁用:

toml 复制代码
[feedback]
enabled = false

Reasoning 噪音hide_agent_reasoning = true 在 CI 日志里特别有用------免得满屏都是模型的内心独白;show_raw_agent_reasoning = true 反过来把模型的原始 reasoning 露出来,但有些模型(比如 gpt-oss)压根不发原始 reasoning,开了也没效果。


十二、企业环境:requirements.toml 是上层硬约束

如果你在受管的公司机器上跑 Codex,组织可能下发了 requirements.toml。这个文件不是普通配置层 ------它独立于上面那六层,作用是强制约束某些键的取值

打个比方:你的 config.toml 是你自己拟的合同条款,requirements.toml 是公司法务定的红线,你的合同条款再怎么写都不能突破红线。

它能干这些事:

  • allowed_approval_policies 限定 approval_policy 只能用哪几种
  • allowed_sandbox_modesdanger-full-access 禁掉
  • [mcp_servers] 白名单 + 身份匹配(command 或 url 必须对得上才让连)
  • [rules] 强制下发的命令规则(只能 prompt 或 forbidden,不能 allow------意思是企业策略只能"加严",不能"放宽")

普通用户大概率碰不到,但 IT 给你下了一个的话,知道它存在能帮你少踩坑------比如发现自己改了 sandbox_mode 不生效,第一反应就该是去看 requirements.toml


写在最后

把这一切串起来,你会发现 Codex 的配置哲学其实很清晰:

分层 ------ CLI flag 临时改、profile 切场景、项目层定制、用户层放共享默认,每一层各司其职。

信任 ------ 项目级 .codex/ 必须显式 trust 才会加载,把"克隆个仓库就被偷家"这种攻击面前置堵死。

正交 ------ 审批策略(问不问)和沙箱模式(能干啥)独立配置,可以组合出"全自动但只读"或者"逐项确认但全权限"这种细致姿态。

显式 ------ web_search = "cached" 默认走索引而不是实时抓、network_access = false 默认不联网、KEY/SECRET/TOKEN 自动过滤------这些默认安全的选择写得明明白白。

可观测 ------ /debug-config 能直接打出层级和优先级,排错不用瞎猜。

~/.codex/config.toml 打开,对照这篇回头看一眼自己的配置。大概率你会发现至少三个之前没注意到、但其实应该改一下的键。

相关推荐
imbackneverdie2 小时前
AI生成论文插图速度快不用手搓,但是怎么变成矢量图?
图像处理·人工智能·ai作画·aigc·科研绘图·ai工具·ai生图
92year2 小时前
用 Python 从零实现 LLM 多模型熔断降级——asyncio + 自动切换实战
aigc
甲维斯2 小时前
GLM5.1 降智了?国模思考强度研究!
人工智能·ai编程
Restart-AHTCM2 小时前
AI 时代的大前端崛起,TypeScript 重塑前端开发
前端·人工智能·typescript·ai编程·a
却尘2 小时前
Codex CLI 30+ 斜杠命令全拆解:一个 `/` 让你少敲一万次键盘
aigc·openai·ai编程
littleM2 小时前
深度拆解 HermesAgent(五):记忆系统与用户建模
jvm·人工智能·架构·ai编程
pczpcz82 小时前
openclaw连接shopify
ai编程
Code_Artist3 小时前
一天之内我让 AI 用 Netty 造了一个最小可用的 MVC 框架:体验一下造轮子的快感😅!
后端·netty·ai编程
littleM3 小时前
OpenClaw vs HermesAgent 对比分析系列
人工智能·架构·ai编程