改完 `config.toml` 不生效:按这四层覆盖顺序往下查

2026-08-09

改了 ~/.codex/config.toml,保存,重开一个会话,行为跟没改一样——这是 Codex(OpenAI Codex)用户最常撞的一类问题。它烦人的地方在于:没有任何报错。你只能对着配置文件反复看,怀疑是键名拼错了,然后把值改来改去试。

大多数时候,键名没拼错。问题出在配置的覆盖层上:你写的那个值在生效之前,被前面某一层截胡了;或者那个文件压根就没被读进去。

下面这四层要按顺序查。顺序是有讲究的——第一层没排除掉就去查第三层,你会得到一堆自相矛盾的观察结果。

第一层:这个配置文件到底加载成功了没有

这一层排第一,是因为它最容易被跳过,而它一旦出问题,后面三层查什么都是白费。

判定命令(只读,安全):

codex doctor --summary

看输出里 Configuration 分组的 config 那一行。正常是 config (loaded)

这里有一条本机实测的结论,值得单独拎出来说。在 codex-cli 0.147.0(Windows 11)上,我故意喂了一段语法不合法的 TOML:

codex -c 'features=[unclosed' doctor --summary

命令没有崩溃退出,doctor 照常从头跑到尾,只是在 Notes 区多出了一行:

✗ config       config could not be loaded - Fix the reported config error, then rerun codex doctor.

这个设计很反直觉:配置坏了,CLI 不会拒绝启动,它会带着一份空配置继续跑。所以你看到的”改完不生效”,可能压根不是”这个键不生效”,而是”整个文件都没加载”。这里要说清楚边界:本机验证过的是数组没闭合这一种,而且走的是命令行 -c 覆盖这条路径;其它 TOML 语法错误(以及写在 config.toml 文件里的语法错)是否同样只在 doctor 的 config 行里体现,我们没有逐一试过。但反过来是成立的——只要这一行是 ,就说明配置没读进去,不必再往下查了。

除了语法错,还有两种”文件没被读”的情况:

  • 你编辑的不是它读的那个文件。 官方 Configuration Reference 页写明配置位置是 $CODEX_HOME/config.toml,默认 ~/.codex/config.toml。如果 CODEX_HOME 被指向了别处(容器、CI 镜像、多账号切换脚本里很常见),你手改的那个文件跟它读的就不是同一个。
  • 命令本身要求不加载。 codex exec --ignore-user-config 的官方说明是不加载 $CODEX_HOME/config.toml;注意它有个细节——auth 仍然使用 CODEX_HOME。也就是说登录状态是好的,配置是空的,从表面症状看特别像”配置不生效”。

处置:修掉 TOML 语法问题,或者把 CODEX_HOME / 启动命令理顺。

处置后怎么验证:重跑 codex doctor --summary,那一行从 变回 ✓ config (loaded) 才算过。doctor 的状态符号有四种:(ok)、(idle)、(notes/warn)、(fail),结尾还有一行统计,形如 17 ok · 1 idle · 1 notes · 0 warn · 0 fail。要把诊断结果贴给同事或者贴进 issue,用 codex doctor --json——官方说明是 “Emit a redacted machine-readable report”,是脱敏的。

第二层:命令行上的一次性覆盖

配置加载成功了,但你这次启动时在命令行上带的参数,优先级在配置文件之上。

最常见的三类:

  • -c, --config <key=value>:覆盖 ~/.codex/config.toml 里的值。点号路径表示嵌套(foo.bar.baz)。官方给的三个例子是 -c model="o3"-c 'sandbox_permissions=["disk-full-read-access"]'-c shell_environment_policy.inherit=all
  • --enable <FEATURE> / --disable <FEATURE>:可重复,官方明说等价于 -c features.<name>=true / =false。所以你在配置文件里关掉的特性,可能被启动脚本里的一个 --enable 又打开了。
  • -s, --sandbox <SANDBOX_MODE>-m, --model <MODEL> 这类专用选项,同样是本次会话覆盖。

-c 这里藏着一个很阴的行为:value 按 TOML 解析,解析失败则按字面字符串处理。它不报错,它给你降级。所以 -c 后面写了个本该是布尔或数组的值但引号没配对,你拿到的会是一个字符串,而不是一条错误提示。

判定方法:把你实际敲的那条命令原样看一遍——包括 shell 别名、封装脚本、任务计划里的那条。然后把这些参数全部去掉,只跑最裸的启动方式,看行为是否回到配置文件里写的样子。

反过来也能用:把你正在纠结的那个键放到命令行上跑一次,如果这时行为变了,说明键名和取值都是对的,问题就在”配置文件那一侧的加载/覆盖”,可以直接回第一层和第三层。

第三层:profile 叠加层

这一层是多环境用户的重灾区。

-p, --profile <CONFIG_PROFILE_V2> 的官方说明是:把 $CODEX_HOME/<name>.config.toml 叠加到基础用户配置之上。也就是说你的配置根本不在一个文件里——基础的 config.toml 一份,profile 一份,后者压前者。你在 config.toml 里改的键,如果 profile 文件里也写了同名键,你的修改就被盖掉了。

这里还有一个特别容易搞混的地方:-p-P 是两套完全不同的东西

  • -p, --profile:上面说的配置层叠加。
  • -P, --permission-profile <NAME>:套用配置栈里的命名权限档,对应配置里的 permissions.<name>.* 那一整块(extendsworkspace_rootsfilesystemnetwork 等),另有 default_permissions 指定默认档名。

改权限相关的键没生效时,先确认自己改的是哪一套。

另外,企业机器上还有一层你改不动的:官方 Configuration Reference 里,auto_review.policy 标注了「受管配置优先」,guardian_policy_config 是「受管 Markdown 评审策略,覆盖本地策略」。如果你在公司发的设备上折腾这两块,本地怎么写都可能被上层策略盖掉。

验证:去掉 -p 参数跑一次做对照。两次行为不同,就锁定在 profile 层。

第四层:这个键在你这台机器上本来就不生效

前三层都排除了,还有最后一种可能:键写对了、文件加载了、没人覆盖你,但这个键在你这个平台或这个版本上就是不起作用

平台差异。 最典型的是 features.unified_exec,官方标注默认 true,但括号里跟了一句 Windows 除外。在 codex-cli 0.147.0(Windows 11)上跑 codex features listunified_exec 的生效值确实是 false,和文档口径对得上。你在 Windows 上把它写成 true 然后期待行为变化,方向就错了。Windows 侧还有几个专属键:windows.sandbox(取值 unelevatedelevated)、windows.sandbox_private_desktop(默认 true),以及 hooks 里的 commandWindows仅 Windows 的命令覆盖)。

特性阶段。 codex features list 输出三列:特性名、阶段、当前生效值。在 0.147.0 上观测到的阶段共五种:stableunder developmentexperimentaldeprecatedremoved。几个直接影响判断的例子(同样是 0.147.0 / Windows 11 的实测行):

特性阶段生效值
code_modeunder developmentfalse
token_budgetunder developmentfalse
network_proxyexperimentalfalse
web_search_cacheddeprecatedfalse
steerremovedtrue

前两行是 under development,第三行是 experimental——这类开关别当稳定功能用,配了没动静是正常的。

deprecated 那一行则指向另一个高频错法:features.web_search / web_search_cached / web_search_request 这三个键官方已标注均已弃用,要改用顶层 web_search。顶层 web_search 默认值是 cached,取值为 disabled / cached / indexed / live——默认既不是关闭也不是实时。你在 features 表里配了半天搜索行为没变,多半就是配在了废弃键上。CLI 侧开实时搜索对应的是 --search

removed 这一行最容易误读:removed 阶段的特性仍然会出现在 list 里,而且部分 removed 项的生效值是 true(比如 steer)。这说明 “removed” 指的是这个开关本身不再需要你控制、行为已经固化,不等于功能没了。看到 removed 就去配置里加一行想把它打开,是白做工。

配置内部还有覆盖关系。 MCP 那块,disabled_tools 官方明确写着enabled_tools 之后生效。两个都配的时候以 deny 为准——你在 enabled_tools 里加的工具,会被 disabled_tools 里的同名项吃掉。

处置后统一怎么验证

改完别急着开会话试感觉,先用只读命令把”生效值”看出来:

你改了什么用什么看看哪里
任何配置codex doctor --summaryConfiguration 组的 config
sandbox_mode / approval_policycodex doctor --summaryConfiguration 组的 sandbox
features.*codex features list第三列「生效值」
mcp_servers.*codex mcp listStatus / Auth

在 codex-cli 0.147.0(Windows 11)上,doctor 的 sandbox 行输出形如 restricted fs + restricted network · approval OnRequest,沙箱模式和审批策略一眼就能对上,比开个会话去感受靠谱得多。codex mcp list 的表头是 Name | Command | Args | Env | Cwd | Status | Auth,其中 Env 列的值会被打成 *****、只显示键名;但 Command / Args / Cwd 三列是原样输出,可能带上你的本地路径,往外贴之前自己再过一眼。

还有一条前置动作:每次排查先跑 codex --version。本机实测过一个挺离谱的场景——同一台机器上,采集开头 codex --versioncodex-cli 0.131.0,十几分钟后再敲同一条命令变成了 0.147.0which -a codex 全程只有一个可执行文件。Codex 有自更新能力(配置里 check_for_update_on_startup 默认 true),所以”昨天的版本号”不能拿来当排查依据,一切以当次 codex --version 的实时输出为准。默认值和特性阶段都会随版本变。

什么情况说明不是配置覆盖的问题

别一条道走到黑。出现下面几种迹象,就该换方向了:

1. doctor 显示 config (loaded),且 codex features list 里那一项的生效值确实是你写的值。 配置层已经清白了,接着查的应该是这个键本身管的是不是你以为的那件事。

2. 加了 --strict-config 没报错,不代表键名拼对了。 --strict-config 的官方说明是 config.toml 里出现本版本不认识的字段时直接报错退出。但在 0.147.0(Windows 11)上,我故意把键名拼错跑了一次:

codex -c model_reasoning_effortt=high --strict-config exec --help

结果是正常打印 help,没有任何未知字段报错。说明这项校验发生在真正加载配置去跑会话的路径上,--help 这种不进入会话的路径不触发。所以别把它当成”任何情况下都能拦住拼写错误”的保险。

3. MCP server 起不来,先别怀疑配置写错。 startup_timeout_sec 默认只有 10 秒,慢启动的 server 必须显式调大;required 为真时,启用的 server 初始化失败会让整个启动失败。这些是超时和依赖问题,不是覆盖问题。

4. 沙箱里写文件没落盘,那是沙箱在干活。 在 0.147.0(Windows 11)上实测:用 codex sandbox 执行一条把内容重定向到仓库内文件的命令,命令返回后目标文件并不存在。这是默认沙箱状态下的预期行为,跟 config.toml 有没有生效是两回事。

5. 现象只出现在桌面应用或 IDE 上。 官方 Troubleshooting 页里有一条:功能在 CLI 有、桌面应用没有,原因是两个面的 Codex 版本不同,官方给的做法是分别查版本——CLI 用 codex --version,macOS 应用用 /Applications/Codex.app/Contents/Resources/codex --version。桌面应用与 IDE 扩展我们没有实测,这里只转述官方口径。

一段可以直接抄的对照配置

想快速验证”这一层通不通”,可以先把配置压到最小,只留你正在排查的那几个键:

model_reasoning_effort = "high"
sandbox_mode = "workspace-write"

[sandbox_workspace_write]
network_access = false

[windows]
sandbox = "elevated"

[mcp_servers.example]
command = "node"
args = ["server.js"]
startup_timeout_sec = 120

其中 [windows] sandbox = "elevated"startup_timeout_sec = 120 是本机 config.toml 里实际存在的写法。以上为按官方文档键位组合的示例,未逐项实测,以官方文档为准。

写完保存,按顺序过一遍:codex doctor --summaryconfigsandbox 两行 → codex features list 看生效值 → codex mcp list 看 Status。三处都对上,才算这次修改真的落地了。

相关阅读


本文依据 Codex 官方文档(learn.chatgpt.com/docs/ 的《Configuration Reference》《Troubleshooting》页面)整理,核对日 2026-08-09;文中标注「本机实测」的部分基于 codex-cli 0.147.0 / Windows 11 环境下的只读命令输出。产品功能、模型与价格以官方最新说明为准。桌面应用与云端部分为官方文档口径,非本机实测。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。