春江暮客

春江暮客的个人学习分享网站

Codex 总在 /tmp 留下文件?一步步配置自动清理

2026-10-14 技术
Codex 总在 /tmp 留下文件?一步步配置自动清理

Codex 做完任务后,运行中创建的辅助脚本、下载文件和测试日志还留在 /tmp。次数多了,不仅占空间,也很难分清哪些文件可以删除。

解决办法是给每个任务分配独立临时目录,明确告诉 Codex 何时清理,再让创建目录的代码负责自动删除。对于本地 Codex CLI,还可以用启动脚本在前台命令退出后清理整个会话的临时目录。

本文面向有基本终端操作经验的 Linux 和 WSL 用户,处理的是为你的任务创建的临时文件。Codex 自身的运行时文件、持久状态和工具缓存可能有不同的生命周期。

选择清理方法

方法 清理时机 适用场景
AGENTS.md 规则 Codex 完成任务时 项目或用户的长期指令
Bash EXIT trap 所属 shell 退出时 一次 shell 操作,包括命令失败
Python TemporaryDirectory 退出 with 代码块时 Python 脚本,包括普通异常
CLI 启动脚本 本地前台 Codex 命令退出时 会话级补充清理

先加入指令规则,再给临时脚本加上自动清理。 如果还想在 CLI 会话结束时清理,可以继续配置启动脚本。指令可以约束智能体的行为,但不能保证进程崩溃、被 SIGKILL 终止或关机后还能执行删除。

第 1 步:先检查文件,不急着删除

在 Codex 实际执行命令的 Linux 环境中运行:

codex --version
du -sh /tmp
if [ -d /tmp/codex-work ]; then
  du -sh /tmp/codex-work
  find /tmp/codex-work -mindepth 1 -maxdepth 1 -type d -print
fi

这一步只是查看现状。/tmp 其他位置的文件不一定属于 Codex 任务,不能确认归属的文件先保留。下面的步骤会让新建文件有明确的归属和清理范围。

本文参数已对照本机 Codex CLI 0.162.1 和官方 CLI 文档核对。如果你的版本不同,先查看 codex --help。

第 2 步:在 AGENTS.md 中加入长期规则

如果只希望规则作用于当前项目,在仓库根目录打开 AGENTS.md:

nano AGENTS.md

如果希望所有项目默认遵守,在 Codex 用户目录打开指令文件:

mkdir -p "${CODEX_HOME:-$HOME/.codex}"
nano "${CODEX_HOME:-$HOME/.codex}/AGENTS.md"

把下面的段落追加到现有文件,保留其他指令:

## Temporary files

- Create a unique directory for each task under /tmp/codex-work/.
- If TMPDIR points to a dedicated Codex session directory, create task
  directories inside that directory instead.
- Put temporary scripts, downloads, logs, and intermediate files there.
- Record the exact task directory you created.
- Save final deliverables in the workspace before cleanup.
- Wait for processes using task files to finish before deleting them.
- Use a Bash EXIT trap or Python TemporaryDirectory when practical.
- Before finishing, delete only your task directory, verify it is gone,
  and report any cleanup failure.
- Never clear all of /tmp, delete other tasks' files, or remove persistent
  Codex state and caches as part of task cleanup.
- The session directory supplied through TMPDIR belongs to the launcher;
  delete your task subdirectory, not the launcher's session directory.

这段规则要求每个任务有独立目录,记录路径,先保存结果、等待相关进程结束,再清理并确认目录消失。如果启动脚本提供会话级 $TMPDIR,任务目录就放在其中;智能体只清理自己的子目录,把会话目录留给启动脚本。

Codex 在启动时读取全局和项目指令。同层级的 AGENTS.override.md 优先于 AGENTS.md,更深层的项目指令可以覆盖前面的规则。修改后重启会话,并确认实际生效的文件。官方 AGENTS.md 文档

在新会话里输入:

Summarize the temporary-file rules you loaded. For this task, record the
temporary directory, save deliverables in the workspace, then delete your
task directory and verify it is gone.

这会把清理列为任务完成的一部分。下面两步把删除直接放进可执行代码,使普通命令失败时也能清理。

第 3 步:用 Bash EXIT trap 自动清理

在项目根目录运行这个完整示例:

bash <<'BASH'
set -euo pipefail
task_base="${TMPDIR:-/tmp/codex-work}"
mkdir -p "$task_base"
task_tmp=$(mktemp -d "$task_base/task-XXXXXXXX")
trap 'rm -rf -- "$task_tmp"' EXIT
printf 'Task directory: %s\n' "$task_tmp"

mkdir -p artifacts
printf 'temporary input\n' > "$task_tmp/input.txt"
tr '[:lower:]' '[:upper:]' < "$task_tmp/input.txt" > "$task_tmp/result.txt"
cp -- "$task_tmp/result.txt" artifacts/cleanup-result.txt
cat artifacts/cleanup-result.txt
BASH

输出会包含本次任务的独立目录,以及:

TEMPORARY INPUT

结果保存在 artifacts/cleanup-result.txt,临时目录在这次 Bash 进程退出时删除。命令失败、set -e 使 shell 退出时,EXIT trap 也会执行。

目录创建、处理和清理必须放在同一个 shell 脚本里。一次工具调用注册的 trap 不能负责另一次独立 shell 的清理。跨多次调用的工作,需要由智能体记录任务目录,最后明确删除。

引号和 -- 让删除命令指向 mktemp 返回的精确目录,不要改成匹配整个 /tmp 的通配符。这个示例使用前台命令;如果启动了子进程,先等它们结束,再让负责清理的 shell 退出。按第 6 步检查清理结果,不要假设删除总能成功。

第 4 步:用 Python TemporaryDirectory 自动清理

把下面代码保存为 cleanup_demo.py,也可以下载完整示例:

#!/usr/bin/env python3
import os
import shutil
from pathlib import Path
from tempfile import TemporaryDirectory

base = Path(os.environ.get("TMPDIR", "/tmp/codex-work"))
base.mkdir(parents=True, exist_ok=True)
output = Path("artifacts/cleanup-result-python.txt")
output.parent.mkdir(parents=True, exist_ok=True)

with TemporaryDirectory(prefix="task-", dir=base) as directory:
    task_tmp = Path(directory)
    print(f"Task directory: {task_tmp}")
    intermediate = task_tmp / "result.txt"
    intermediate.write_text("temporary input\n".upper(), encoding="utf-8")
    shutil.copyfile(intermediate, output)

print(f"Temporary directory exists: {task_tmp.exists()}")
print(f"Deliverable exists: {output.exists()}")

使用 Python 3 运行,无需第三方依赖:

python3 cleanup_demo.py

最后两行应为:

Temporary directory exists: False
Deliverable exists: True

Python 会在退出上下文时删除目录,包括普通异常导致的退出。单独使用 mkdtemp() 需要自己清理,详见 Python tempfile 文档。

临时文件全部写入这个目录,最终结果在离开代码块之前复制出去。先关闭文件句柄,并等待子进程结束。进程被突然终止时,上下文清理也可能无法执行。

第 5 步:给本地 Codex CLI 加上退出清理

还可以加一层启动脚本:创建独立会话目录,设置 TMPDIR,等待前台 CLI 命令结束,再删除目录。CLI 执行失败时,脚本会保留它的退出码。

先在项目中创建 scripts/ 目录,再把下面内容保存为 scripts/codex-clean。也可以下载启动脚本:

#!/usr/bin/env bash
set -euo pipefail
command -v codex >/dev/null 2>&1 || {
  printf 'codex is not on PATH\n' >&2
  exit 127
}

run_root=/tmp/codex-work
mkdir -p "$run_root"
run_tmp=$(mktemp -d "$run_root/session-XXXXXXXX")
readonly run_tmp

cleanup() {
  run_status=$?
  trap - EXIT
  if rm -rf -- "$run_tmp"; then
    printf 'Cleaned session directory: %s\n' "$run_tmp" >&2
  else
    printf 'Cleanup failed: %s\n' "$run_tmp" >&2
    if [ "$run_status" -eq 0 ]; then
      run_status=1
    fi
  fi
  exit "$run_status"
}
trap cleanup EXIT

export TMPDIR="$run_tmp"
printf 'Session directory: %s\n' "$run_tmp" >&2
codex --no-daemon --sandbox workspace-write \
  --add-dir "$run_tmp" \
  -c "shell_environment_policy.set.TMPDIR=\"$run_tmp\"" \
  "$@"

然后执行:

mkdir -p scripts
# Save the launcher above as scripts/codex-clean before running:
chmod +x scripts/codex-clean
./scripts/codex-clean

进入会话后,让 Codex 在 $TMPDIR 中创建任务子目录,并遵守第 2 步的规则。使用完后退出 CLI,启动脚本才会清理会话目录。交互会话还开着时,一条回复完成不会触发启动脚本的 trap。

如果只执行一个非交互任务:

./scripts/codex-clean exec \
  'Use a unique task directory inside TMPDIR for scratch files. Save a short cleanup test report as artifacts/codex-cleanup-report.txt, then remove your task directory and verify it is gone.'

请在你信任的仓库中运行。如果 CLI 停在仓库检查阶段,先解决这个前置问题,再判断清理行为。

启动脚本为会话目录增加写入权限,明确设置工具 shell 的 TMPDIR,并用 --no-daemon 执行本地前台运行。参数见 CLI 文档,环境变量过滤见配置文档。

TMPDIR 是工具约定,不是文件系统隔离。命令如果写死了 /tmp/example,仍可能在会话目录外创建文件;启动脚本只删除自己的目录。远程会话、脱离终端的任务和共享后台服务需要按实际生命周期清理。退出前先结束或停止使用临时文件的进程,需要跨会话恢复的数据应保存在工作区。

第 6 步:验证目录已删除,结果仍然存在

启动脚本会输出类似下面的路径:

Session directory: /tmp/codex-work/session-Ab12Cd34
Cleaned session directory: /tmp/codex-work/session-Ab12Cd34

检查本次运行实际打印的路径。下面的命令让你粘贴路径,避免猜测目录名:

bash <<'BASH'
read -r -p 'Paste the session directory printed by the launcher: ' checked_tmp < /dev/tty
if [ -e "$checked_tmp" ]; then
  printf 'Still exists: %s\n' "$checked_tmp"
else
  printf 'Removed: %s\n' "$checked_tmp"
fi
test -f artifacts/codex-cleanup-report.txt
BASH

执行前面的非交互示例后,应看到 Removed: ...,结果文件检查也应成功。再查看报告内容。模型回复里的一句“已清理”,不如文件系统检查能直接证明结果。如果检查 Bash 示例,则使用它打印的任务路径,以及 artifacts/cleanup-result.txt。

也可以只列出还存在的会话目录,不执行删除:

find /tmp/codex-work -mindepth 1 -maxdepth 1 -type d -name 'session-*' -print

其他目录可能属于仍在运行的会话。父目录不为空,不代表你这次运行清理失败。

第 7 步:常见问题与处理方法

Codex 仍然直接向 /tmp 写文件

让它通过实际工具 shell 输出 $TMPDIR,并在 mktemp -d "$TMPDIR/task-XXXXXXXX" 或 TemporaryDirectory(dir=...) 中明确指定目录。一些工具会忽略 TMPDIR。如果环境策略配置了允许列表,确认其中包含 TMPDIR,不要关闭整套策略。环境变量策略文档

AGENTS.md 的规则没有生效

在目标项目里重新启动 Codex,检查同层级的 AGENTS.override.md。如果设置了 CODEX_HOME,修改该目录内的指令文件。让 Codex 概述当前清理规则。指令发现规则

Permission denied 或启动参数不支持

确认当前用户可以在 /tmp/codex-work 下创建目录,并查看 codex --help。共享服务器上,如果父目录属于其他用户,换成自己拥有且可写的任务目录,同时修改规则和启动脚本。--add-dir 为 workspace-write 模式增加写入目录,但组织策略仍可能限制权限。保留沙箱;如果旧版 CLI 不支持 --no-daemon,先更新 CLI,或使用前面的脚本级方法。

崩溃后目录仍然存在

指令和 EXIT trap 都无法在 SIGKILL 或断电之后执行。确认精确目录属于已停止的运行、没有需要保存的结果后,只删除这个目录。不要按文件年龄直接安排定时删除,长时间运行的任务也可能使用旧文件。自动处理崩溃残留,需要按调度系统设计归属和存活状态检查。

清理成功,但磁盘空间还是没恢复

可能有其他进程仍打开着已经删除的文件。可以继续阅读 Linux 删除文件后磁盘仍满的排查教程。继续删除无关临时文件不能定位这个问题。

总结

在 AGENTS.md 中写清临时文件规则,为每个任务创建独立目录,并在清理前保存结果。Bash trap 和 Python 上下文管理器可以在正常完成和普通失败时自动删除临时文件。本地 CLI 启动脚本还能在命令退出时补充清理;最后检查精确目录是否消失,并把持久结果留在工作区。

标签

1024 12306 ablang adsense agents.md ai ai-agent ai-agents ai-seo algorithm amp antibodies apparmor argparse automation backup bash batch-processing binarycif bioinformatics biopython blockchain boltz bootstrapping boxes bubblewrap c-index cca cdn chatgpt checkpoint cli cloudflare codex cofoldarena copy cpu监控 cron csv cuda curl data-leakage data-processing data-quality data-validation datascience datavisualization debugging deployment desktop-app devtools disk-space disown docker dovecot download electron encoding esm esm2 esm3 esmc esmfold2 faceswap fasta fastmcp faulthandler ffmpeg file-descriptors file-io flashppi flask folium frontend game generator git github-actions google google-research grep gzip harness hls html http hugo indexnow javascript jev json jsonl just k-means kaggle langfuse leecode linux list litellm llm llms.txt logging logs lollipop lsof m3u8 machine-learning macos manacher matplotlib mcp mirror mmcif model-evaluation mp3 mp4 mpnn multiomics mutation mysql nanobert nanobodies networkx nginx normalize numpy ollama omegatherm pandas password pdb pep-723 phaser pillow pip postfix preprocessing print protein-alignment protein-design protein-embeddings protein-interactions protein-language-models protein-stability protein-structure proxy pydantic pyecharts pyqt python python3 r raincloud reproducibility requests reservoir-sampling rfoptimization rg ripgrep rosettafold3 roundcube rrsi rsi rsync s-tui sampling scale scikit-learn scrapy screen seaborn security selenium seo sequence-identity sha256 signals sklearn solana somaticsignatures spl sqlite ssh standardize static-site subprocess sysadmin system-one tensorflow tkinter toml tron tronpy troubleshooting turtle typesafe-ai ubuntu usdt uv vhhbert vite webp wordcloud wordpress workflow yaml 后台 寓言 概率 经济 贸易 迅雷解析 钱包

友情链接

其它