
1. 为什么 Codex 在 workspace-write 下会越权改文件先说清楚 Codex 是什么、能做什么、适合谁。Codex CLI 是 OpenAI 推出的命令行编码代理能在本地工作区里读文件、改代码、跑命令。它有一个workspace-write模式意思是允许代理在沙箱层面直接写入当前工作区而不是每次改动都等你确认。这个模式效率高但问题也出在这里沙箱只保证它不跑到工作区外面去并不保证它只改你心里想的那几个文件。我遇到过的典型场景是这样的。你给 Codex 一个任务“把测试修好”。它读了一圈代码发现src/format.js里的实现和测试断言对不上于是改实现——这是你想要的。但另一种可能是它觉得测试断言写得太严直接把test/format.test.js里的期望值改掉测试也绿了。更隐蔽的是它可能顺手在package.json里加一个格式化依赖或者改README.md里的示例。三种做法都能让npm test通过但改动范围完全不同验收口径也完全不同。这就是“越权改文件”的本质不是 Codex 恶意而是任务描述里没有把边界写清楚它只能自己判断哪些文件“相关”。一旦判断权交给模型结果就不可控。你要做的是把判断权收回来用项目自己的规则文件把允许修改的范围钉死再用git diff和npm test做双重验收。这篇要解决的就是这件事。我会用一个只有 5 个文件的真实小项目codex-agents-guard-demo走一遍完整流程先写AGENTS.md允许修改清单再固定失败基线再给 Codex 下带边界的任务最后用git diff --name-only、文件哈希和npm test退出码逐项核对。同时把 Codex 的 endpoint 和auth.json统一到 TaoToken 的 Key 通道避免每个项目各配一套 Key。适合谁看已经在用或准备用 Codex CLI 做日常编码、被“测试绿了但改动失控”坑过、想给代理加一层可检查约束的开发者。不需要你懂沙箱底层实现跟着命令敲就行。先明确一个前提AGENTS.md不是操作系统权限它只是项目级规则Codex 会读取并尽量遵守但最终是否越界要靠 diff 验证。workspace-write控制的是沙箱能不能写工作区AGENTS.md控制的是“应该写哪些文件”两层叠加之后验收仍然看实际改动。这个认知很重要后面所有步骤都围绕它展开。项目结构长这样一共 5 个文件codes/codex-agents-guard-demo/ ├── AGENTS.md ├── README.md ├── package.json ├── src/format.js └── test/format.test.jssrc/format.js当前只返回标题export function formatBook(book) { return book.title; }测试要求返回Clean Code (2008)这种“标题 (年份)”格式用的是 Node.js 内置的node:test没有第三方依赖。这个项目足够小任何多出来的文件都会在git status里一眼看到适合做边界演示。2. 把 TaoToken 配成 Codex 的统一 Key 通道在写规则之前先把模型服务通道固定下来。Codex CLI 需要知道往哪个 endpoint 发请求、用哪个 Key、调哪个模型。如果每个项目各配一套Key 散落在多个auth.json里既难管理也容易误提交。我的做法是统一走 TaoToken一个 Base URL、一个 Key、一个模型 ID所有项目共用。TaoToken 的 API 地址是https://taotoken.net/api官网入口在https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content。申请 Key 的入口在控制台模型对话调试入口和接入文档也都在官网能找到。下面按 Codex CLI 的实际配置位置来写。Codex CLI 的认证信息默认放在用户目录下的auth.json路径在 Windows 上是%USERPROFILE%\.codex\auth.json在 macOS/Linux 上是~/.codex/auth.json。这个文件里放 Base URL 和 API Key。模型 ID 则在 Codex 的配置文件里指定通常是~/.codex/config.toml或项目级配置。三件套必须齐全Base URL、Key、Model ID缺一个都连不上。先看auth.json的结构。把下面这段里的占位符换成你自己的 Key注意不要提交到 Git{ OPENAI_API_KEY: YOUR_TAOTOKEN_API_KEY, OPENAI_BASE_URL: https://taotoken.net/api }如果你用的是 Codex 的 TOML 配置方式config.toml里对应写模型和 providermodel gpt-5-codex model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY wire_api responses这里env_key指向环境变量名你也可以直接把 Key 写进auth.json。两种方式选一种不要混用。wire_api按当前 Codex CLI 支持的协议填字段以你本地版本和官网文档为准本文不承诺具体模型效果或额度。配好之后用一条最小请求验证通道是否通。Codex CLI 本身有登录/状态检查命令也可以直接跑一个只读任务codex exec 读取当前目录的 README.md用一句话总结它不要修改任何文件如果通道正常你会看到模型返回总结且git status没有任何改动。如果报 401说明 Key 或 Base URL 不对如果报连接失败检查网络和 endpoint 拼写。这一步过了再进入规则编写。关于 Key 的安全有几条硬规矩。真实 Key、Cookie、Authorization 头、完整配置文件都不要放进源码、截图或 Git 历史。文章和示例里统一用YOUR_TAOTOKEN_API_KEY占位。auth.json建议加进.gitignore项目级配置里只留环境变量名。我试过把 Key 写进项目配置然后忘了删提交前靠git diff --check和人工扫一遍才发现这种坑一次就够。统一通道的好处很直接换项目不用重新配Key 轮换只改一处审计时知道所有请求都走同一个出口。TaoToken 在这里扮演的是统一入口不是替代编辑器也不是绕过什么就是把 endpoint 和 Key 收敛到一个地方。接入文档里有更细的字段说明遇到不确定的配置项去官网对照当前版本。3. 可复制的 AGENTS.md 模板与配置片段现在进入核心写AGENTS.md。这个文件放在项目根目录Codex 启动时会读取它作为项目规则。关键原则是——只写可检查的边界。什么叫可检查就是每一条规则都能用一条命令或一个退出码验证真假。“代码要优雅”不可检查“只允许修改src/format.js”可检查因为git diff --name-only能列出实际改动文件。下面是我在这个项目里实际用的AGENTS.md你可以直接复制改路径# 本项目规则 - 只允许修改 src/format.js。 - 不允许修改 test/、README.md、package.json 和本文件。 - 不增加依赖。 - 修改后运行 npm test。 - 不读取或写入 API Key、Cookie、Authorization 或用户私密数据。逐条拆解为什么这样写。第一条“只允许修改src/format.js”验收命令是git diff --name-only -- .输出里除了这个文件之外的任何路径都算越界。第二条把受保护文件列全包括AGENTS.md自己——防止 Codex 为了“让规则更合理”而改规则。第三条“不增加依赖”验收方式是检查package.json的dependencies/devDependencies有没有变化以及有没有新增node_modules之外的文件。第四条“修改后运行npm test”验收方式是保存完整输出和退出码。第五条是安全边界防止代理去读环境变量里的密钥。注意AGENTS.md和workspace-write的关系。workspace-write是沙箱层决定代理能不能写工作区AGENTS.md是项目层决定应该写哪些文件。两层都配了最终仍要看实际 diff。不要以为写了规则就万事大吉规则是给模型看的diff 是给你看的。如果你用 Cline MCP 或 CC Switch 这类工具管理多个代理配置同样要把三件套写全Base URL、Key、Model ID。以 Cline 的 MCP 配置为例片段长这样{ mcpServers: { taotoken: { command: npx, args: [-y, taotoken/mcp-server], env: { TAOTOKEN_BASE_URL: https://taotoken.net/api, TAOTOKEN_API_KEY: YOUR_TAOTOKEN_API_KEY, TAOTOKEN_MODEL_ID: gpt-5-codex } } } }这段里的TAOTOKEN_BASE_URL、TAOTOKEN_API_KEY、TAOTOKEN_MODEL_ID就是三件套缺任何一个 MCP 都起不来。CC Switch 里切换配置时也是同样三个字段别只填 Key 忘了 Model ID。Codex 的auth.json前面已经给过这里不再重复。再强调一次路径一致性。auth.json在~/.codex/auth.jsonconfig.toml在~/.codex/config.toml项目级AGENTS.md在项目根目录。这三个位置不要搞混。我见过有人把AGENTS.md放到src/下面Codex 读不到规则等于没写。规则写完之后先自己跑一遍验收命令确认基线干净git status --short -- .如果这个项目本来就有未提交改动先记录或提交否则任务结束后分不清哪些 diff 是本次产生的。这一步花不了几秒但能省掉后面大量扯皮。4. 固定失败基线并用 git diff 核对改动范围规则和通道都就绪后先固定失败基线。为什么要先跑一次失败的测试因为你要证明“修复前确实是坏的”这样修复后测试变绿才有意义。如果基线本来就是绿的Codex 随便改点什么你都无法判断是不是真修好了。进入项目目录跑测试并记录退出码Set-Location .\codes\codex-agents-guard-demo npm test $LASTEXITCODE真实结果是测试总数 1通过 0失败 1实际值Clean Code期望值Clean Code (2008)退出码 1。这个基线要保存下来后面修复必须对应同一个输入和断言。测试前还要记录工作区状态git status --short -- .如果输出为空说明工作区干净本次任务产生的所有 diff 都是新的。如果有输出先处理掉再继续。接着给受保护文件保存修改前哈希。哈希的作用是快速确认“有没有变”diff 的作用是判断“具体变了什么”两者互补Get-FileHash AGENTS.md,README.md,package.json,test\format.test.js -Algorithm SHA256把输出记下来。任务结束后再算一次逐项对比。如果哈希一致说明这些文件内容没动如果不一致直接停下来查 diff。现在给 Codex 下任务。任务文本里要重复边界因为项目规则负责长期约束任务文本负责这一次的目标两处都写回看记录时不用猜当时的验收口径请先读取当前目录的 AGENTS.md并说明你将遵守的文件范围。 修复 formatBook让它返回“标题 (年份)”格式。 只允许修改 src/format.js。 不要修改测试、README、package.json 或 AGENTS.md不要增加依赖。 完成后运行 npm test并列出实际修改文件和测试退出码。任务跑完后按顺序执行验收命令。第一条看改了哪些文件git status --short -- . git diff --name-only -- .合格结果里只应该出现src/format.js。如果test/format.test.js、README.md、package.json或AGENTS.md出现在列表里先停下来检查测试通过也不能抵消范围越界。第二条看具体改了什么git diff -- .\src\format.js重点检查实现有没有硬编码Clean Code (2008)。如果它直接把期望值写死返回测试也会绿但这是作弊不是修复。正确做法是根据book.title和book.year拼接。第三条检查空白和冲突标记git diff --check -- .这条命令会报出多余空白、冲突标记等问题输出为空才算干净。第四条重新算受保护文件哈希和之前记录的逐项对比Get-FileHash AGENTS.md,README.md,package.json,test\format.test.js -Algorithm SHA256第五条跑测试并看退出码npm test $LASTEXITCODE合格标准是只修改src/format.js、没有新增依赖、实现没有硬编码、受保护文件哈希一致、git diff --check无报错、npm test全部通过且退出码为 0。六条全过才算验收完成。5. 常见报错排查401、local proxy failed、reading choices、OAuth配置和验收过程中会撞到几类固定报错逐个说清楚原因和解法。第一类401 Unauthorized。这个最常见原因是 Key 或 Base URL 不对。先确认auth.json里的OPENAI_API_KEY是 TaoToken 控制台申请的那串不是别的平台的。再确认OPENAI_BASE_URL是https://taotoken.net/api结尾不要多斜杠也不要少路径。如果用的是环境变量方式检查env_key指向的变量名和实际导出的变量名是否一致。改完重启 Codex CLI配置是启动时读的。第二类local proxy failed。这个报错通常出现在代理配置或网络层。先检查有没有残留的代理环境变量比如HTTP_PROXY、HTTPS_PROXY把它们清掉再试。然后确认 endpoint 能直连用一条最小请求验证。如果公司网络有出口限制找网络管理员确认taotoken.net是否可达。不要用任何绕过网络管理的方式合规第一。第三类reading choices 相关报错。这类错误一般出现在响应解析阶段说明返回结构和你配置的wire_api不匹配。检查config.toml里的wire_api字段按当前 Codex CLI 版本支持的协议填。如果模型 ID 写错也可能返回非预期结构。三件套里 Model ID 最容易写错对照官网文档确认拼写。第四类OAuth 相关报错。Codex CLI 某些版本支持 OAuth 登录流程如果你混用了 OAuth 和 API Key 两种认证方式会冲突。统一走 Key 通道的话确认没有残留的 OAuth token 文件。清理掉旧的登录态只用auth.json里的 Key。如果报错信息里出现回调地址相关字样说明它在尝试 OAuth 流程检查配置里有没有误开相关选项。第五类测试通过但 diff 越界。这个不是报错但比报错更危险。表现是npm test退出码 0但git diff --name-only里出现了受保护文件。处理方式是回滚越界改动重新下任务把边界写得更死。如果 Codex 反复越界把AGENTS.md里的规则改成更具体的路径并在任务文本里用“禁止”而不是“不要”。第六类git diff --check报空白错误。这通常是编辑器或代理写入了行尾空格、制表符混用。用git diff --check定位到具体行手动修掉或者让 Codex 只修这一处。别忽略它空白错误积累多了会让后续 diff 难以阅读。排查的通用顺序是先看退出码再看报错关键词再对照三件套Base URL、Key、Model ID最后看 diff 范围。大部分问题出在配置字段拼写和路径不一致上。把auth.json、config.toml、AGENTS.md三个文件的位置和内容核对一遍能解决八成问题。6. 把统一通道和边界规则固化进日常流程走到这里你已经有了完整的一套AGENTS.md写清允许修改清单TaoToken 统一 Base URL、Key、Model ID 三件套git diff核对范围文件哈希确认受保护文件没动npm test退出码做最终验收。这套流程的价值不在于某一次修复而在于它可以重复用在每个项目上。日常使用时我会把验收命令写成一个脚本放在项目根目录任务结束后一条命令跑完所有检查。脚本内容就是前面那五条命令的顺序组合输出里任何一项不合格就退出非零码。这样不用每次手动敲也不会漏检查项。关于 Key 通道再补一个实用技巧。如果你有多个项目把auth.json放在用户目录共用项目级只放AGENTS.md和业务代码。这样 Key 只有一份轮换时改一处。项目级配置里如果需要覆盖模型 ID用项目级config.toml但 Base URL 和 Key 仍然继承用户级。这样既统一又灵活。AGENTS.md的规则可以随项目演进。比如项目变大后允许修改的文件从一个变成三个就在清单里逐个列出不要写“src 目录下所有文件”这种模糊表述。越具体越可检查。如果某个文件只是偶尔需要改就把它排除在默认清单外需要时在任务文本里单独授权而不是放宽长期规则。最后说一个我踩过的坑。有一次任务描述里写了“修复测试”但没写边界Codex 把测试文件改了测试绿了我差点直接提交。后来靠git diff --name-only发现测试文件在列表里才拦下来。从那以后我下任务前一定先确认AGENTS.md在项目根目录、内容是最新的任务文本里再重复一遍边界。两道保险缺一不可。需要申请 Key 或查接入文档去 TaoToken 官网控制台和文档页想先试模型对话效果用模型对话入口长期做编码和 Agent 任务看 Coding Plan。API 地址统一用https://taotoken.net/api配置字段以你本地 Codex CLI 版本和官网当前说明为准。把三件套配好把AGENTS.md写死剩下的交给git diff和npm test说话。