上周三晚上十一点多,我正用 Codex CLI 的 full-auto 模式跑一个批量重构任务——大概 40 多个文件的 import 路径要统一改掉。跑了大概二十分钟,我听到笔记本风扇开始狂转,打开 iotop 一看:Codex 的沙箱进程在以 180MB/s 的速度往 /tmp 写东西。当时我的 512G SSD 剩余写入寿命已经只剩 78% 了,吓得我直接 kill -9

Codex CLI 在 full-auto 模式下会触发高频文件写入,根因是沙箱的 allow-write 策略默认覆盖了整个 /tmp 目录且没有写入速率限制,导致模型生成的中间文件(diff patch、执行日志、临时脚本)在循环任务中无限堆积。解决方案有三种:收紧沙箱为 read-only 再显式开白名单、用 tmpfs 内存盘隔离临时写入、或用 inotify + 脚本做写入限速熔断。

这篇适合谁

  • 在用 Codex CLI full-auto 模式跑批量任务,发现磁盘 IO 异常高的人
  • 想搞清楚 Codex 沙箱到底允许写哪些路径、怎么收紧权限的开发者
  • Linux 服务器上部署 Codex CLI 做 CI/CD 自动修复,需要保护磁盘的 DevOps
  • 单纯好奇"AI 写代码怎么还能把 SSD 写穿"的吃瓜群众

整体流程

  1. 复现问题——确认 full-auto 模式下高频写盘的触发条件
  2. 定位根因——分析沙箱 writable_roots 默认策略和 /tmp 未隔离的问题
  3. 方案一:--sandbox=read-only + 显式白名单(最安全)
  4. 方案二:tmpfs 内存盘挂载替代物理磁盘(最省 SSD)
  5. 方案三:inotify 监控 + 写入限速熔断(更灵活)
  6. 根据场景选方案
graph TD
 A[Codex full-auto 启动] --> B{沙箱写入策略}
 B -->|默认: CWD + /tmp 可写| C[中间文件无限堆积]
 C --> D[SSD 高频写入 180MB/s]
 D --> E{选择保护方案}
 E --> F[方案一: read-only + 白名单]
 E --> G[方案二: tmpfs 内存盘]
 E --> H[方案三: inotify 限速熔断]

先说结论

方案 保护效果 性能影响 适合场景
read-only + 白名单 最强,彻底杜绝意外写入 可能中断任务需重跑 生产 CI/CD、不信任任务内容
tmpfs 挂载 强,写入不落盘 占用内存(建议预留 2G) 开发机日常使用
inotify 限速 中等,超阈值才熔断 几乎无 需要保留写入能力但防失控

第一步:复现高频写盘的触发条件

触发条件挺具体的:循环性任务 + full-auto + 默认沙箱配置。用下面这条命令可以稳定复现:

codex --approval-mode full-auto 'refactor all files in src/ to use absolute imports, fix each file one by one'

跑起来之后用 iotop -a -o -P-a 累计模式,-o 只显示有 IO 的进程,-P 只显示进程不显示线程)观察,大概 3 分钟后写入速率就会飙上去。原因是 Codex 对每个文件生成 diff patch 写到 /tmp/codex-* 目录,而循环任务不会清理前一轮的临时文件。

实测数据:40 个文件的重构任务,跑完 /tmp 下堆了 2.3GB 的临时文件,全是 .patch.log

第二步:定位根因——沙箱默认策略过宽

查看当前配置:

cat ~/.codex/config.yaml

配置文件中 sandbox.writable_roots 默认包含两个路径:当前工作目录(CWD)和 /tmp。问题就出在 /tmp 这里——它没有容量限制也没有速率限制。

注意sandbox.writable_roots 是本文使用的配置字段名,实际字段名称请以 codex --help 或官方文档为准,不同版本可能有差异。

macOS 上的沙箱是 Apple Seatbelt(sandbox-exec),Linux 上是 Docker 或 Landlock+seccomp。不管哪个平台,/tmp 都被标记为可写。这个设计本身没错——很多构建工具确实需要写临时文件——但缺了一个"写入总量上限"的兜底。

第三步(方案一):read-only 沙箱 + 显式白名单

把沙箱收紧到只读,然后只开放确定需要写入的目录:

# ~/.codex/config.yaml
sandbox:
  writable_roots:
    - "/home/user/myproject/src"

这样 /tmp 就不可写了。如果任务确实需要写临时文件,它会报错:

PermissionError: [Errno 1] Operation not permitted: '/tmp/codex-abc123/patch.diff'

看到这个报错说明沙箱在正常工作。如果任务必须写临时文件,往 writable_roots 加一个专用子目录就行,别给整个 /tmp

sandbox:
  writable_roots:
    - "/home/user/myproject/src"
    - "/tmp/codex-limited"

然后手动建这个目录并设置配额(下一步讲)。

第四步(方案二):tmpfs 内存盘挂载

让 Codex 继续写 /tmp,但 /tmp 本身是内存盘,不落物理磁盘,SSD 写入量大幅降低。

sudo mount -t tmpfs -o size=2G tmpfs /tmp/codex-sandbox

然后把 config 里的 writable_roots 指向这个挂载点:

sandbox:
  writable_roots:
    - "/home/user/myproject/src"
    - "/tmp/codex-sandbox"

tmpfs 满了之后写入会直接失败,相当于自带容量熔断。2G 对绝大多数重构任务够用了。实测跑了一周,最大一次用了 1.4G。

重启后 tmpfs 会丢失,想持久化就加到 /etc/fstab

tmpfs /tmp/codex-sandbox tmpfs size=2G,mode=1777 0 0

第五步(方案三):inotify 监控 + 写入限速熔断

不改沙箱配置,在外面套一层监控。写入事件累计超过阈值就自动终止 Codex 进程。

先装 inotify-tools(大多数 Linux 发行版都有包):

sudo apt install inotify-tools

然后写个监控脚本,codex-guard.sh

#!/bin/bash
# 累计写入事件超过 THRESHOLD 次则触发熔断
# 注意:这是累计计数模式,不是滑动时间窗口;如需滑动窗口请自行扩展
THRESHOLD=500
LOGFILE=/var/log/codex-guard.log

# 记录 Codex 进程 PID,避免 pkill 模式匹配不准
CODEX_PID=$1
if [ -z "$CODEX_PID" ]; then
  echo "Usage: $0 <codex_pid>" >&2
  exit 1
fi

COUNT=0
while read -r event; do
  COUNT=$((COUNT + 1))
  if [ "$COUNT" -gt "$THRESHOLD" ]; then
    kill "$CODEX_PID" 2>/dev/null
    echo "[$(date)] Codex PID $CODEX_PID killed: write event count exceeded $THRESHOLD" >> "$LOGFILE"
    exit 0
  fi
done < <(inotifywait -m -r /tmp --format '%e' 2>/dev/null)

使用方式:先启动 Codex,记下其 PID,再启动守护脚本:

codex --approval-mode full-auto '...' &
CODEX_PID=$!
bash codex-guard.sh "$CODEX_PID"

与方案二相比,这个方案适合需要保留完整写入能力、但想防止事件风暴的场景。计数阈值需要根据实际任务规模调整,正常重构任务写入事件通常远低于 500 次。

不同场景怎么选

个人开发机(macOS/Linux 桌面):方案二 tmpfs 最省心。挂载一次就完事,不用改工作习惯,SSD 写入量大幅降低。内存 16G 以上的机器拨 2G 出来压力不大。

CI/CD 服务器:方案一 read-only 白名单。生产环境不能容忍任何意外写入,宁可任务失败重跑也不要磨盘。CI 里 Codex 用的 o4-mini 模型 input $1.10/M tokens(以 OpenAI 官方定价为准,请自行核实当前价格),跑一次重构任务大概 ¥0.3–0.8,失败重跑成本可以忽略。

需要保留完整写入能力但怕失控:方案三 inotify。比如你在用 Codex 做代码生成任务,生成的文件本身就需要落盘,但想防止循环写入风暴。

混合方案(我现在用的):tmpfs + inotify 双保险。tmpfs 保护 SSD,inotify 在内存盘快满之前就熔断,避免 OOM。

踩坑记录 / 常见问题 FAQ

Q: Codex full-auto 模式下 npm install 会被 read-only 沙箱拦截吗?

会。npm install 要往 node_modules 写文件,如果你的 writable_roots 没包含项目目录就会报 PermissionError。解决办法是把项目根目录加到白名单里——反正你本来就要让 Codex 改这个目录的代码。

Q: macOS 上 sandbox-exec 报 Operation not permitted 怎么办?

按顺序查:① 确认 Codex CLI 支持的 macOS 最低版本(以官方文档为准);② 确认 /usr/bin/sandbox-exec 存在;③ 检查 SIP 状态(csrutil status),确认 SIP 处于开启状态——SIP 被关闭时 sandbox-exec 的强制约束可能失效,表现为沙箱限制不生效而非报错。我上个月在一台 Hackintosh 上踩过这个坑,折腾半天发现是装黑苹果时把 SIP 关了。

Q: tmpfs 方案会不会导致 Codex 任务中途 crash?

会。tmpfs 满了写入会返回 ENOSPC(No space left on device),Codex 进程会直接退出。所以 size 要给够,建议 2G 起步。如果你的任务经常处理大型 monorepo(几百个文件),给 4G。

Q: Linux 上 Landlock+seccomp 方案内核版本不够怎么办?

内核版本低于 5.13 的话 Landlock 不可用,Codex 会 fallback 到 Docker 容器沙箱。如果 Docker 也没装,会报 Error: Docker daemon not running。这时候要么升内核,要么装 Docker,要么退回 auto-edit 模式手动确认写入操作。

Q: 怎么确认我的 Codex 版本支持 writable_roots 配置?

codex --version 看版本号。2025 年 4 月之后发布的版本均支持(Codex CLI 于 2025 年 4 月底开源)。老版本如果在 config.yaml 里写了 sandbox.writable_roots 会被忽略但不报错——静默失败比较难排查,建议升到最新版再配置。

小结

Codex CLI full-auto 模式的高频写盘问题,根源在于默认策略对 /tmp 的写入没有总量限制。循环任务加上无限制的临时文件堆积,对 SSD 损耗较大。三种方案各有适用场景,个人日常用 tmpfs + inotify 双保险跑了快两周,再没出现过写入风暴。磁盘健康度稳定在 78% 没再掉——虽然这个数字本身已经让我有点焦虑了。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐