context-infra 检查与复盘infra.guiming.net · 全内容自包含呈现 · 生成于 2026-07-21 16:28 UTC

Codex 调度 Loop(调度 / Heartbeat / Resume)

Z3 全文↑ Z2 条目

术-运行时 · 术层 skill 全文

← 返回术层 skill 索引 · 返回方法论区

本页是 <code>rules/skills/codex_schedule_loop.md</code> 的逐字投影(仅隐私清洗,零改写)。

时点提示:本页是仓内文件 rules/skills/codex_schedule_loop.md 的逐字投影(仅做隐私清洗:仓库根绝对路径→相对路径、家目录→~/;除此零改写)。若源文件后续有修订,以仓内真源为准。

Skill:Codex 调度 Loop(调度 / Heartbeat / Resume)

使用时机

需要选择 Codex App automation、cron/CI、codex exec resume,或检查已有 codex cloud 任务时参考本 skill。典型触发词:schedule loop、定时、heartbeat、automation、自动检查、每天/每周运行、轮询、检查状态、resume、重新开始。

本 skill 只回答运行在哪里、什么时候醒来、怎么查看和恢复。它不定义修改 / 验证 / 保留或丢弃,不定义 requirements verdict,不创建 task card,不决定业务 closure。Codex 自调用、调 Claude Code、以及 Codex runtime execution contract 统一放在 codex_self_evoke_call_claude_code_loop;上层 Controller 任务契约放在 workflow_controller_loop

目标

为一个 Codex schedule loop 任务选出最小可行调度方式,并留下可检查、可恢复的状态。完成后必须能回答五个问题:什么时候运行、在哪个 workspace 运行、怎么查看结果、怎么继续/重跑、什么条件下停止或上报。

执行模式

模式用途状态与检查
Codex App thread 自动化同一对话需要按分钟/天/周醒来继续;适合检查长命令、PR 状态、review loop、持续调研当前 thread + Codex App Automations 面板 / Triage
Codex App standalone/project 自动化每次 run 独立;适合日报、issue triage、CI 摘要、跨一个或多个 project 的周期性扫描Automations 面板 / Triage;Git repo 可选 local 或独立 worktree;必须保留 automation run record
codex exec + cron/launchd/GitHub Actions需要脚本化、文件日志、CI、仓库自管状态机;适合 context-infra 这类已有 cron 管线stdout/stderr 日志、--json events、--output-last-message、自定义 state file
codex exec resume / codex resume已有 session 要续接;或失败后带上下文补跑保存 session id/thread name 和 rollout;禁止 --ephemeral
codex cloud已委派到 Codex Cloud 的任务需要列表、状态、diff、apply只用于检查已有 cloud task record;不能替代需要保存本地聊天/rollout 的 wakeup fallback

当前仓库已有两类参考实现:

短周期持续 Controller Loop

当用户要求 sustained Controller Loop、持续测试、监控与控制机制,或 20 分钟级唤醒时,优先使用同一 thread heartbeat,除非用户明确要独立 project/worktree automation。默认 cadence 是每个 Loop Unit 之间约 20 分钟;用户明确指定更长或更短间隔时,以用户指定为准。不要把持续 Loop 设成每天或每周,除非用户明确要求低频运行。

本 skill 只设置调度面。业务状态必须留在任务目录,例如 REQUIREMENTS.mdCONTROL.md.loop_trace/state.jsonloop_state.codex.jsonnext_prompt.codex.mdPROGRESS.mdHANDOFF.mdevidence/debug/evidence/reviews/

20 分钟 heartbeat prompt 必须要求每次醒来:

决策规则

必需运行契约

创建或实现定时任务前,先把这些字段写进 prompt、automation 描述、wrapper 脚本注释或状态文件:

这些字段只描述调度和观测。业务状态、证据判断、issue class 和下一步允许/禁止动作必须写入任务目录的 Controller/runtime 状态文件,不能只写在 automation 描述里。

超时、重试与健康检查

任何无人值守的 codex exec + cron/launchd/CI wakeup 都必须有防卡机制。不能只依赖人手工查看 launchctl print 或 run 目录。

最低要求:

状态解释:

状态含义允许反应
exit_code=0 且非空 last_message.md本轮完成进入下一轮或等待下一 tick
state=running 且 run dir 增长本轮仍活跃等待
state=running 且超过 timeout、events/rollout 不增长卡死终止进程树,写 timeout evidence,释放 lock
连续 timeout 达阈值系统性故障风险写 pause file,停止自动重试,等待人工或上层 Controller 决策
lock 存在但 owner pid 不存在陈旧 lock记录并释放 lock,然后按正常策略继续

Codex App 自动化

在 Codex App 里能使用 automation 工具时,优先让 Codex 创建或更新 automation,而不是手写内部配置。描述任务、schedule、是否绑定当前 thread、是否使用 project/worktree、模型/推理强度即可。

如果当前工具面暴露 automation_update,并且用户要求 sustained Loop / schedule wakeup / heartbeat,必须直接创建或更新 thread heartbeat。只写 SCHEDULER_DECISION.md、只描述应当如何调度、或把创建动作推给未来 Agent,都不算完成调度。只有工具不可用、权限不足、用户禁止、或调度会触发明确安全风险时,才允许降级为 verified fallback / manual resume / blocked,并把原因写入 Controller 状态。

线程型 automation 的 prompt 要持久:说明每次醒来要做什么、如何判断没有新发现、何时停止或请求用户输入。项目型 automation 默认把 findings 放进 Triage;如果选择 worktree,定期归档不再需要的 runs,避免频繁 schedule 产生过多 worktree。

创建 automation 前必须确认该面会保留 App thread/run 记录;如果当前工具或权限只能触发一个无聊天记录的后台命令,不得把它登记为 Codex wakeup 方法,只能改走保留 session 的 codex exec wrapper 或等待可用的 App automation。

安全默认值:Git repo 中优先使用 worktree;只有明确希望直接修改当前 checkout 时才用 local。后台 automation 是无人值守执行,默认按当前 sandbox 设置运行;需要写文件、联网或操作本机 app 时,先确认权限与风险边界。

Controller Loop 中的 Codex 调度写法

workflow_controller_loop 选择 scheduled_codex_runtime 时,本 skill 只设置调度面。Controller 文件仍是业务真相源。

同一 thread heartbeat 的 prompt 必须包含:

project/standalone automation 的 prompt 必须包含:

codex exec + cron/CI 的 wrapper 必须保留 prompt、events JSONL、stderr、last message、exit code、开始/结束时间,并把 resume pointer 写回 Controller/runtime 状态文件。wrapper 禁止传 --ephemeral,也禁止在 run 结束后清理 rollout 或 session 索引。wrapper 还必须有 timeout / retry / stale-lock handling:一个 stuck run 不能阻塞所有后续 wakeup。

本地 scheduler fallback 的健康状态不能只看 job 已注册。launchd / cron / CI wrapper 创建后,至少要完成一次 foreground run 或 launchctl kickstart 等价验证,看到 run directory、exit_code=0、非空 events.jsonlturn.completed 和非空 last_message,才能写成 verified。若只看到 launchctl print 里有 label 或 interval,状态最多是 created_pending_first_success。脚本语法检查和 plist lint 只是静态检查,不能替代首次成功运行。

macOS launchd runner 用 zsh/bash 时避免使用 shell 保留或特殊变量名作为局部变量,例如 zsh 的 status。失败日志必须保留到 run directory 并写入 Controller/runtime state,避免 silent retry。

本地后台启动要使用真正脱离父 shell 的调度面。临时 agent shell 里的 cmd &nohup ... & 可能会被宿主工具回收,不能作为 fallback 验证依据。macOS 一次性或周期性后台启动优先使用已有 cron/launchd wrapper 或 LaunchAgent plist,并显式控制 KeepAlive / StartInterval / RunAtLoad;不要把 launchctl submit 当作一次性模板,除非 wrapper 有锁、去重和每次唯一 RUN_DIR,因为快速退出的 submitted job 可能被 keepalive/minimum-runtime 语义重复拉起。每次 cron/launchd run 必须分配唯一 run directory,避免重复启动覆盖 events.jsonl、stderr 和 last message。

本地 launchd fallback 的推荐自愈策略是:StartInterval 负责重跑;wrapper 负责超时退出和释放锁。不要在同一个 wrapper 里无限递归自调用。若需要更快重试,可由 wrapper 写 retry_recommended evidence,由外层 scheduler 或人工 launchctl kickstart 触发;连续失败达到阈值后必须 pause。

本地 scheduler fallback 不能长期静默运行。它只能作为 Codex App automation 不可用、权限不足、或用户明确要求本地调度时的降级方案。创建 launchd/cron fallback 时必须同时写明:

如果 fallback 已经被创建但没有这些停止/回收字段,状态只能写成 fallback_created_without_lifecycle_contract,不能写成 verified。后续 agent 的第一步应补齐 lifecycle contract 或停用该 fallback。

CLI 与 Cron 模式

直接用 Codex CLI 时,先以当前机器的 codex exec --help 为准核对 flags,再保持 agent invocation 的 durable output 规则。当前 CLI 的 approval 行为来自配置/profile;不要把旧示例中的 --ask-for-approval 写进新 wrapper,除非本机 codex exec --help 明确支持该 flag。当前 CLI 暴露 --ephemeral,但 scheduler/runtime wrapper 一律不得使用它。

codex exec \
  --sandbox workspace-write \
  --cd "$WORKSPACE" \
  --json \
  --output-last-message "$RUN_DIR/last_message.md" \
  - < "$RUN_DIR/prompt.md" \
  > "$RUN_DIR/events.jsonl" \
  2> "$RUN_DIR/stderr.log"

生产 wrapper 不应裸跑上面的命令;应把它放进 timeout/watchdog 块。超时退出码统一用 124,并写 timeout report。伪代码:

codex exec ... > "$RUN_DIR/events.jsonl" 2> "$RUN_DIR/stderr.log" &
pid=$!
deadline=$(( $(date +%s) + WAKEUP_TIMEOUT_SECONDS ))
while kill -0 "$pid" 2>/dev/null; do
  if [ "$(date +%s)" -ge "$deadline" ]; then
    terminate_process_tree "$pid"
    echo 124 > "$RUN_DIR/exit_code.txt"
    write_timeout_report
    release_lock
    exit 124
  fi
  sleep 5
done
wait "$pid"
echo "$?" > "$RUN_DIR/exit_code.txt"

续接非交互 session:

codex exec resume "$SESSION_ID" \
  --json \
  --output-last-message "$RUN_DIR/resume_last_message.md" \
  "Continue from the last recorded state. Re-check the current workspace before editing." \
  > "$RUN_DIR/resume_events.jsonl" \
  2> "$RUN_DIR/resume_stderr.log"

云任务检查:

codex cloud list --json --limit 20
codex cloud status "$TASK_ID"
codex cloud diff "$TASK_ID"
codex cloud apply "$TASK_ID"

Cloud 命令只检查或应用已有 cloud task。不要把 cloud status check 写成新的 Codex wakeup fallback,除非同时有可追溯的 cloud task record,并且任务自己的 Controller ledger 记录了该 task id。

可观测性

来源


← 返回术层 skill 索引 · 返回方法论区