主流 Agent 入门教程 / Codex
13. 用codex-exec实现自动化
原文备份 · 第 14 / 27 篇 · 查看极客时间原知识库 ↗
本篇目录 · 17 节
来源:Codex
预计学习时间:55—70 分钟
本篇目标:用codex exec为 TaskFlow 生成可验证的健康报告,理解普通输出、JSONL 事件、结构化结果、退出状态和自动化权限边界。
前面几篇一直在 Codex 的交互界面里工作。交互模式适合需求还在变化、需要随时追问和纠偏的任务;当一套检查已经稳定,并且你希望从脚本、定时任务或 CI 中反复运行时,才轮到 codex exec。
codex exec 是 Codex CLI 的非交互模式。它接收一次任务说明,执行后退出,不需要你守在 TUI 里继续对话。它适合做下面这些工作:
- 重复执行仓库健康检查;
- 把测试日志整理成固定格式;
- 为后续脚本输出 JSON;
- 在 CI 中生成供人审查的报告或补丁。
“非交互”不等于“可以放心给最高权限”。恰恰因为运行期间没人临时纠偏,工作目录、沙箱、输入、输出和完成条件更需要提前写清楚。
这一篇继续使用 TaskFlow。我们会先跑一个只读命令,再逐步把它升级成既给人看、也能被脚本消费的健康检查。
一、先确认自动化的运行环境
进入 TaskFlow 仓库根目录。先执行:
codex --version
codex login status
git rev-parse --show-toplevel
git status --short
这些命令在 PowerShell 中相同。
你需要确认:
- Codex CLI 能正常运行;
- 当前已经登录;
- Git 输出的根目录正是 TaskFlow;
- 你知道自动化开始前有哪些未提交改动。
codex exec 默认要求在 Git 仓库中运行。这个限制能减少在错误目录里执行任务的风险。--skip-git-repo-check 适合你完全了解的临时目录,不应该成为项目脚本里的默认选项。
再查看本机版本真正支持的参数:
codex exec --help
教程里的命令以当前稳定参数为准;如果帮助中没有某个选项,先更新 Codex,而不是直接照抄执行。
二、第一次运行:明确使用只读沙箱
在 TaskFlow 根目录执行:
codex exec --sandbox read-only "检查当前 TaskFlow 仓库,概括项目结构、完整测试命令和三个最值得关注的发布风险。只读取和分析,不修改文件。每个结论给出文件或命令证据。"
PowerShell 中可以使用同一条命令。
运行过程中,进度信息会写到 stderr,最终回复写到 stdout。因此终端里可能先看到工具调用和进度,最后才出现一段完整结论。这是正常现象。
命令结束后,先检查退出码。
macOS、Linux 或 WSL:
echo $?
Windows PowerShell:
$LASTEXITCODE
退出码为 0 说明这次 codex exec 运行完成,不代表 TaskFlow 一定健康。项目是否通过,仍要看测试证据和报告里的状态。这是自动化中非常重要的区别:进程成功结束与业务检查通过不是一回事。
再执行:
git status --short
结果应该与运行前一致。这个检查独立证明只读任务没有悄悄改动项目。
官方对输出流、沙箱和非交互模式的说明见 Non-interactive mode。
三、把最终回复单独保存,而不是重定向所有日志
先创建输出目录。
macOS、Linux 或 WSL:
mkdir -p reports
Windows PowerShell:
New-Item -ItemType Directory -Force reports | Out-Null
然后运行:
codex exec --sandbox read-only \
--output-last-message reports/taskflow-health.md \
"只读检查 TaskFlow 的测试、README 与实际 CLI 是否一致,并生成一份简洁的 Markdown 健康报告。列出实际证据、阻塞项和未能验证的内容。不要修改项目文件。"
PowerShell 可以写成一行:
codex exec --sandbox read-only --output-last-message reports\taskflow-health.md "只读检查 TaskFlow 的测试、README 与实际 CLI 是否一致,并生成一份简洁的 Markdown 健康报告。列出实际证据、阻塞项和未能验证的内容。不要修改项目文件。"
-o 是 --output-last-message 的短写。它只把 Agent 最终回复写入指定文件,进度仍然显示在终端。打开文件验证内容:
macOS、Linux 或 WSL:
sed -n '1,240p' reports/taskflow-health.md
Windows PowerShell:
Get-Content reports\taskflow-health.md
一份合格的报告至少要说明:
- 它检查了哪些文件和命令;
- 完整测试是否真的运行;
- README 与当前参数是否一致;
- 哪些结论有证据,哪些仍未验证;
- 是否存在发布阻塞项。
如果文件只有“项目结构良好,可以发布”这一类结论,说明任务描述还不够可审计。
不希望保留会话记录时,可以加:
codex exec --ephemeral --sandbox read-only "只读总结当前项目"
--ephemeral 不保存这次运行的 session 文件,适合一次性检查;需要稍后 resume 的多阶段任务不要使用它。
四、不要让管道掩盖原始测试是否失败
你可以把命令输出通过标准输入交给 codex exec:
python3 -m unittest discover -s tests -v 2>&1 \
| codex exec --sandbox read-only "分析输入的测试日志,归纳失败测试、共同根因和建议的排查顺序。只分析,不修改文件。"
但这条简短写法有一个陷阱:管道最后显示的退出码通常来自 codex exec,不一定是前面的测试命令。测试明明失败,日志分析却成功完成,整个管道仍可能得到 0。
更稳妥的做法是先保留测试日志和测试退出码,再交给 Codex 分析。
macOS、Linux 或 WSL:
python3 -m unittest discover -s tests -v > reports/tests.log 2>&1
test_exit=$?
codex exec --sandbox read-only \
"读取 reports/tests.log,归纳失败测试、共同根因和下一步。报告中必须注明原始测试退出码为 ${test_exit}。只分析,不修改文件。"
codex_exit=$?
echo "tests=$test_exit codex=$codex_exit"
PowerShell:
py -m unittest discover -s tests -v *> reports\tests.log
$testExit = $LASTEXITCODE
codex exec --sandbox read-only "读取 reports/tests.log,归纳失败测试、共同根因和下一步。报告中必须注明原始测试退出码为 $testExit。只分析,不修改文件。"
$codexExit = $LASTEXITCODE
"tests=$testExit codex=$codexExit"
最终你会得到两个独立状态:
tests:TaskFlow 测试本身是否通过;codex:Codex 是否完成日志分析。
自动化脚本不应该把它们混成一个结果。日志中如果含有令牌、客户数据、本机敏感路径或生产内容,要先脱敏,再交给模型处理。
五、JSONL 记录的是过程事件,不是一份普通 JSON 报告
当下游系统需要观察运行过程时,可以使用 --json:
codex exec --json --sandbox read-only \
"只读核对 README 中的命令是否与当前 TaskFlow CLI 一致。" \
> reports/codex-events.jsonl
PowerShell:
codex exec --json --sandbox read-only "只读核对 README 中的命令是否与当前 TaskFlow CLI 一致。" > reports\codex-events.jsonl
此时 stdout 不再只是最终回复,而是 JSON Lines:每一行都是一个独立 JSON 对象。常见事件包括 thread 开始、turn 开始或结束、命令执行、文件变化、Agent 消息和错误。
先查看前几行。
macOS、Linux 或 WSL:
sed -n '1,12p' reports/codex-events.jsonl
Windows PowerShell:
Get-Content reports\codex-events.jsonl -TotalCount 12
你应该看到多行各自完整的 JSON,而不是一个最外层数组。不能直接把整份 .jsonl 当成普通 .json 交给只接受单个 JSON 文档的解析器。集成时应逐行读取,并对未知事件类型保持兼容。
如果你只关心最终结论,用 -o;如果你需要工具调用、进度、用量或失败事件,用 --json。二者可以同时使用。
六、用 JSON Schema 固定最终结果
人读 Markdown 很舒服,程序更需要稳定字段。现在为 TaskFlow 健康检查准备一个 Schema。
创建 schemas/taskflow-health.schema.json:
{
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": ["pass", "warn", "fail"]
},
"summary": { "type": "string" },
"checks": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": { "type": "string" },
"status": {
"type": "string",
"enum": ["pass", "warn", "fail", "unknown"]
},
"evidence": { "type": "string" }
},
"required": ["name", "status", "evidence"],
"additionalProperties": false
}
},
"blockers": {
"type": "array",
"items": { "type": "string" }
}
},
"required": ["status", "summary", "checks", "blockers"],
"additionalProperties": false
}
如果你正在 Codex 交互界面中,可以让它按上面内容创建文件;创建后要亲自打开核对。Schema 只规定报告长什么样,并不决定什么证据算通过。
再创建 prompts/taskflow-health.md:
对当前 TaskFlow 仓库执行只读健康检查。
检查范围:
1. 运行 AGENTS.md 规定的完整测试;
2. 核对 README 的命令、参数和默认行为;
3. 检查当前 Git Diff 是否包含真实运行数据、缓存、明显密钥或个人绝对路径;
4. 检查 TaskFlow 1.0 JSON 数据是否仍可读取。
要求:
- 不修改任何项目文件;
- 只把实际执行或读取到的内容写为证据;
- 无法验证的检查标为 unknown;
- 任一发布阻塞项存在时,顶层 status 为 fail;
- 没有阻塞但存在提醒时为 warn;
- 全部有证据通过时才为 pass。
把提示词放进文件有两个好处:版本控制可以审查它,shell 也不必处理一大段引号和 $ 等特殊字符。
macOS、Linux 或 WSL 执行:
codex exec --json --sandbox read-only \
--output-schema schemas/taskflow-health.schema.json \
--output-last-message reports/taskflow-health.json \
- < prompts/taskflow-health.md \
> reports/taskflow-health.events.jsonl
Windows PowerShell:
Get-Content prompts\taskflow-health.md -Raw | codex exec --json --sandbox read-only --output-schema schemas\taskflow-health.schema.json --output-last-message reports\taskflow-health.json - > reports\taskflow-health.events.jsonl
这里同时产生两个文件:
reports/taskflow-health.json:符合 Schema 的最终结果;reports/taskflow-health.events.jsonl:完整事件流。
--output-schema 约束最终回复的结构,不能证明里面的判断一定正确。打开并验证 JSON 语法:
macOS、Linux 或 WSL:
python3 -m json.tool reports/taskflow-health.json
Windows PowerShell:
py -m json.tool reports\taskflow-health.json
然后再对照完整测试、README 和 Git Diff 检查 evidence。只有结构正确而证据空泛,仍然不是一份可靠报告。
七、让脚本同时判断“运行成功”和“检查通过”
假设 codex exec 返回 0,但报告中的 status 是 fail,自动化仍应失败。可以用 Python 标准库读取最终结果。
macOS、Linux 或 WSL:
python3 -c 'import json,sys; d=json.load(open("reports/taskflow-health.json", encoding="utf-8")); print(d["status"], d["summary"]); sys.exit(1 if d["status"] == "fail" else 0)'
echo $?
Windows PowerShell:
py -c "import json,sys; d=json.load(open('reports/taskflow-health.json', encoding='utf-8')); print(d['status'], d['summary']); sys.exit(1 if d['status'] == 'fail' else 0)"
$LASTEXITCODE
这一步把“模型运行是否完成”和“项目健康检查是否通过”分开:
- 先检查
codex exec的退出码; - 再检查结构化报告里的业务状态;
- 两者任意一个失败,流水线都不应该宣告成功。
对于 warn 是否阻塞,可以按团队规则调整。入门阶段先让 fail 返回非零即可。
八、什么时候允许 codex exec 修改工作区
默认只读很适合报告、分类和审查。如果任务确实需要修改代码,必须显式开放:
codex exec --sandbox workspace-write \
"根据 AGENTS.md 修复当前唯一一个已经复现的失败测试。只做最小修改,先运行局部测试,再运行完整测试,最后汇报 Diff。"
非交互任务无法像你坐在 TUI 前那样随时解释需求。第一次执行新的写入流程时,最好先在可丢弃分支或 worktree 中试跑,并保留人工 Diff 审查。
不要为了减少阻塞而默认使用:
--dangerously-bypass-approvals-and-sandbox
它会绕过审批和沙箱,只适合外层已经有严格隔离的专用环境。日常仓库脚本应使用最小沙箱;需要额外目录时,优先精确使用 --add-dir,不要直接扩大到整个系统。
九、恢复一次非交互任务
如果自动化确实分两个阶段,而且第一阶段保留了 session,可以在同一仓库中运行:
codex exec resume --last "继续上一次检查。先核对当前 Git 状态,只完成尚未执行的验证,然后输出最终结论。"
--last 默认选择当前工作目录最近的非交互会话。更稳妥的自动化可以从 JSONL 的 thread.started 事件中保存 thread ID,后续用明确 ID 恢复:
以下为参数模板,执行前先将尖括号占位符替换为实际值:
codex exec resume <SESSION_ID> "继续第二阶段验证"
不要用 --last 跨多个并发任务猜会话,也不要对 --ephemeral 运行安排后续恢复。
十、接入 CI 前先守住凭据边界
本地练习会复用你已经保存的 Codex 登录。到了 CI,凭据、仓库代码和自动执行会同时出现,风险更高。
一个稳妥的流水线通常是:
运行项目测试
↓
保留退出码并脱敏日志
↓
Codex 在只读仓库中生成结构化报告或补丁
↓
把结果保存为构建产物
↓
人工决定是否修复、合并或发布
GitHub Actions 场景优先使用官方 openai/codex-action。不要把 API Key 设置成整个 Job 都能读取的环境变量,因为仓库里的构建脚本、测试和依赖生命周期脚本也可能读到它。官方建议让密钥只在运行 Codex 的受控步骤中可用,并把生成补丁与拥有仓库写权限的步骤分开。完整示例和安全说明见 Non-interactive mode。
这套入门教程不要求你立即搭建 CI。先把本地只读流程跑通、把输出字段稳定下来、明确什么状态会阻塞,再搬进流水线,排错成本会低很多。
十一、常见问题先看这五项
1. 提示“不是 Git 仓库”
先运行 git rev-parse --show-toplevel,确认工作目录。正式项目应回到仓库根目录;只有可丢弃的临时目录才考虑 --skip-git-repo-check。
2. 没有生成 -o 指定的文件
检查父目录是否已经创建、codex exec 退出码是否为零、Schema 文件是否有效。-o 不会替你建立缺失的复杂目录结构。
3. JSONL 无法被普通 JSON 解析器打开
这是预期行为。它是“一行一个 JSON 对象”,不是一个数组。逐行解析,或者只使用 -o 保存最终 JSON。
4. 命令完成了,但报告说 fail
两者不矛盾。退出码说明 Agent 运行状态,报告字段说明 TaskFlow 健康状态。脚本要同时判断。
5. 非交互任务卡在权限或外部工具上
减少任务范围,显式设置沙箱,移除不必要的网络或 MCP 依赖。无人值守任务如果需要新的人工批准,应该失败并报告,而不是偷偷放宽权限。
本篇小结
codex exec 的价值不是把交互式提示词原样塞进脚本,而是把一套已经验证的流程变成输入、权限、输出和判定规则都明确的命令。
我们为 TaskFlow 完成了一个只读健康检查:普通模式给人看,-o 保存最终回复,--json 记录 JSONL 事件,--output-schema 固定机器可读结果,再由独立脚本同时判断 Codex 退出码和报告状态。整个过程中,Git 状态、真实测试和 Diff 仍然是最终证据。
到这里,TaskFlow 主线已经覆盖了从规划、开发、调试到扩展与自动化的完整流程。接下来的三篇将进入综合实战:先接手陌生仓库修复缺陷,再完成跨文件功能,最后做代码审查、重构和发布准备。