1. 为什么我要认真对待 Codex 沙箱的三种模式
Codex 沙箱的 read-only、workspace-write、danger-full-access 三种权限模式,本质上是在回答一个问题:AI 帮你写代码的时候,它到底能动你系统里的哪些东西。read-only 只能看不能改,适合代码审查和方案分析;workspace-write 能读写当前项目目录、跑测试、装临时依赖,是日常改码的默认档;danger-full-access 则放开网络和系统路径限制,适合受控环境下的全权任务,比如联网装包、调外部 API。这套分级对独立开发者、小团队、以及任何把 AI 接进真实项目的人都直接相关——你不可能永远用最宽松的权限,也不该一直缩在最保守的档位里。
我自己的触发点很具体:有次让 Codex 帮忙重构一个 Flask 项目的目录结构,它顺手把.git/下的东西也动了,虽然没造成不可逆损失,但那次之后我开始认真读它的权限模型。Codex 的沙箱不是 Docker 那种完整虚拟化,而是内核层面的访问控制——macOS 走 Apple Seatbelt,Linux 走 bubblewrap 加 seccomp 和 Landlock。理解这一点很关键:它限制的是进程能碰什么,而不是给你一个独立文件系统。所以模式选错,后果是真实的。
这篇会把三种模式的适用边界、config.toml骨架、以及怎么通过 TaoToken 统一 Key 和 API 通道接进来,一步步写清楚。每个模式我都会给可复制的验证命令和回退动作,你照着做就能在自己的项目里落地。
2. TaoToken 前置:统一 Key 与 API 通道
在配 Codex 之前,先把模型通道理顺。Codex 本身是执行框架,它需要调用背后的模型来完成推理和代码生成。TaoToken 在这里的角色是提供一个统一的 API 入口,你拿一个 Key 就能走通模型对话、编码任务这些场景,不用在多个平台之间来回切换配置。
你需要先拿到 API Key。进入控制台的 API Keys 页面创建一个,建议按用途命名,比如codex-dev,方便后面区分。创建后把 Key 复制出来,它只会完整显示一次。
拿到 Key 之后,Codex 侧需要配置两个东西:API 基地址和 Key。基地址用https://taotoken.net/api,这个地址不带任何查询参数,直接填进配置即可。Key 就是你刚创建的那串。
如果你还没创建 Key,可以先去控制台操作:
控制台入口:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite
创建 Key 的页面:
API Keys 管理:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite
这一步做完,你手上应该有一个可用的 Key 和一个 API 基地址。接下来就是把它写进 Codex 的配置,并和沙箱模式配合起来。
3. 可复制配置:config.toml 骨架与三种模式
Codex 的配置集中在config.toml里。下面这份骨架把模型通道和沙箱模式都覆盖了,你可以直接拿去改。
# ~/.codex/config.toml # 模型通道:走 TaoToken 统一入口 model_provider = "taotoken" model = "claude-sonnet-4-20250514" [model_providers.taotoken] name = "TaoToken" base_url = "https://taotoken.net/api" env_key = "TAOTOKEN_API_KEY" # 沙箱模式:三选一,按任务风险切换 # read-only | workspace-write | danger-full-access sandbox_mode = "workspace-write" # workspace-write 下的额外可写路径(可选) [sandbox_workspace_write] writable_roots = ["/Users/you/projects/myapp"] network_access = falseKey 不要硬编码进文件,用环境变量传:
export TAOTOKEN_API_KEY="sk-你的Key"三种模式的切换,最直接的方式是改sandbox_mode这一行,然后重启 Codex 会话。也可以在启动时用命令行参数临时覆盖:
# 只读审查 codex --sandbox read-only # 日常改码(默认) codex --sandbox workspace-write # 受控全权 codex --sandbox danger-full-access这里有个容易踩的点:workspace-write默认不允许网络访问。如果你在这个模式下让 Codex 去pip install或npm install,它会失败。这不是 bug,是设计。需要联网装包时,要么临时切到danger-full-access,要么在[sandbox_workspace_write]里把network_access打开——但后者要清楚你在放开什么。
三种模式的能力对照,我整理成一张表:
| 能力 | read-only | workspace-write | danger-full-access |
|---|---|---|---|
| 读项目文件 | 允许 | 允许 | 允许 |
| 写项目文件 | 禁止 | 允许 | 允许 |
| 读写系统临时目录 | 禁止 | 允许 | 允许 |
| 启动子进程 | 禁止 | 允许(受约束) | 允许 |
| 网络访问 | 禁止 | 默认禁止 | 允许 |
| 写系统路径(/etc、~/.ssh) | 禁止 | 禁止 | 允许 |
| 修改 .git/ | 禁止 | 禁止 | 允许 |
这张表是选择模式的依据。看任务需要碰哪一列,就往右切一档,任务结束切回来。
4. 逐模式验证:命令、输出与回退
配置写完不算数,得验证每个模式的实际行为。下面三个验证按风险从低到高来,每个都带回退动作。
4.1 read-only 验证:确认它真的不写
先切到只读模式,让它尝试创建一个文件:
codex --sandbox read-only exec "在当前目录创建一个 test_readonly.txt,写入 hello"预期结果是操作被拒绝,输出里会出现类似sandbox: read-only mode, write denied的提示。如果它真的创建了文件,说明你的模式没生效——检查config.toml里sandbox_mode是否被命令行参数正确覆盖,以及有没有其他配置文件在更高优先级上覆盖了它。
回退动作:read-only 本身没有副作用,验证完直接切回workspace-write即可。
4.2 workspace-write 验证:确认项目内可写、项目外不可写
这个模式要验证两件事。第一,项目目录内能正常改:
cd ~/projects/myapp codex --sandbox workspace-write exec "在项目根目录创建 sandbox_test.md,写入一行测试内容"预期是文件成功创建。第二,项目目录外不能写:
codex --sandbox workspace-write exec "在 /tmp 下创建 outside_test.txt"预期是被拒绝,因为/tmp不在writable_roots里。如果你把/tmp加进了writable_roots,那这条就会通过——所以验证前先确认你的writable_roots配置。
回退动作:删掉测试文件rm sandbox_test.md,确认没有残留。
4.3 danger-full-access 验证:确认网络通了,但系统路径仍受控
这个模式放开网络,验证装包能力:
codex --sandbox danger-full-access exec "pip install requests --dry-run"预期是能正常解析依赖、输出安装计划。如果这一步失败,检查你的网络环境是否能访问包源,以及TAOTOKEN_API_KEY是否设置正确——模型通道不通的话,Codex 根本走不到执行装包这一步。
同时验证系统路径仍然受保护:
codex --sandbox danger-full-access exec "尝试写入 /etc/test_danger.txt"预期是被拒绝。danger-full-access放开的是网络和部分系统路径,但不是无差别全开。真正无保护的是--yolo参数,那个会跳过所有确认,日常不要用。
回退动作:danger-full-access下装过的包会真实留在环境里。验证完用pip uninstall requests清理,或者干脆在虚拟环境里做这个验证。
5. 本篇常见错排查
报错一:sandbox_mode不生效,改了 config.toml 还是老行为。最常见的原因是命令行参数覆盖了配置文件。codex --sandbox read-only的优先级高于config.toml。检查你启动时有没有带--sandbox参数,以及有没有CODEX_SANDBOX_MODE这类环境变量在起作用。
报错二:workspace-write 下装包失败,提示网络不可达。这是预期行为。workspace-write默认network_access = false。要么切danger-full-access,要么在配置里显式打开网络——但打开之前想清楚这个项目是否真的需要。
报错三:模型请求 401 或连接失败。先确认TAOTOKEN_API_KEY环境变量在当前 shell 里真的存在:echo $TAOTOKEN_API_KEY。如果为空,说明 export 没生效或者开在了另一个终端窗口。再确认base_url填的是https://taotoken.net/api,没有多余斜杠或路径。
报错四:danger-full-access 下改了 .git/ 导致仓库状态异常。这个模式允许修改.git/,如果 Codex 执行了git相关操作且出了岔子,用git status和git reflog排查。预防办法是:需要全权模式时,先git stash或提交当前改动,让工作区干净。
报错五:切换模式后行为没变,像是缓存了旧配置。Codex 会话启动时读取配置,运行中改config.toml不会热生效。退出当前会话重新启动。
排查顺序建议固定下来:先看环境变量,再看命令行参数,最后看配置文件。这三层的优先级是从高到低的,大部分"配置不生效"都是被更高优先级的层覆盖了。
6. 按风险等级落地你的配置
三种模式不是让你选一个一直用,而是按任务风险动态切换。我的习惯是:默认停在workspace-write,需要审查代码或分析方案时切read-only,需要联网装包或调外部接口时临时切danger-full-access,任务结束立刻切回。
如果你还在配 Key 和通道的阶段,先把 API Key 建好:
API Keys 管理:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite
配置过程中遇到接入问题,对照文档排查:
接入文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite
想先验证模型通道是否通,可以直接在对话页面发一条测试消息:
模型对话:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=model-chat&utm_campaign=rewrite
如果你打算长期用 Codex 做编码和 Agent 任务,Coding Plan 会比按次调用更划算,适合高频场景:
Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite
最后给一个我实际在用的检查清单,每次切换模式前过一遍:当前任务需要写文件吗?需要联网吗?需要碰项目目录外的路径吗?三个问题答完,模式就定了。答完还是不确定,就从read-only开始,不够再往右切——往右切容易,往左收需要你主动想起来。