OmXautoresearch命令契约全解:从 CLI parity 到 runtime 状态机的实现指南
【免费下载链接】oh-my-codexOmX - Oh My codeX: Your codex is not alone. Add hooks, agent teams, HUDs, and so much more.项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-codex
导读
本文深入解析 OmX(oh-my-codex)中omx autoresearch命令的 parity contract(一致性契约),它是驱动"一次 Codex 实验会话 + OMX 持久化 keep/discard/reset 循环"这一研究自动化的核心规范。文章将结合 docs/contracts/autoresearch-command-contract.md 与 src/autoresearch/runtime.ts、src/autoresearch/contracts.ts 等源码,完整讲解 CLI 语法、mission/sandbox 契约、运行时文件布局、候选产物完整性规则、keep/discard 决策策略与 resume 语义。读完本文,你将掌握如何构建一个基于 git worktree 隔离、可断点续跑、以评估器(evaluator)打分为准绳的自动化研究循环,并理解该命令当前在仓库中"硬弃用、runtime 保留"的真实演进状态。
契约定位:thin supervisor 与 OMX 的职责边界
omx autoresearch本质上是一个轻量监督者(thin supervisor):每个迭代只驱动一个Codex 实验会话,而"长期持有的 keep/discard/reset 循环"由 OMX 全权负责。这一职责划分在源码中体现为两层:
- 会话层:每个迭代启动一次 Codex 会话,会话只做"至多一次候选提交",写入候选产物(candidate artifact)后退出——对应的指令模板见 buildAutoresearchInstructions;
- 持久层:OMX 负责运行评估器、根据结果决定保留或丢弃、把工作区重置回最后保留的提交,并把这些状态写入仓库根目录下的运行工件。
从源码结构看,这个契约层经历了完整的演进:CLI 入口 src/cli/autoresearch.ts 已声明该命令hard-deprecated(硬弃用),直接 CLI 启动、--resume、tmux 分屏启动等旧命令面均已不可用;但底层 runtime(src/autoresearch/runtime.ts,共 1300+ 行)与契约解析(src/autoresearch/contracts.ts)完整保留,并演化为 skill-first 的$autoresearch状态化工作流(见 skills/autoresearch/SKILL.md)。因此,本文所述的 parity contract 既是理解旧命令的历史基线,也是理解当前 skill 实现底层循环的最佳入口。
CLI 命令面
契约规定的命令语法如下:
omx autoresearch <mission-dir> [codex-args...] omx autoresearch --resume <run-id> [codex-args...] omx autoresearch --help三条核心语义:
- 全新启动(fresh launch)总是创建一条带 run-tag 的新车道(lane):每次全新启动都会生成独立的运行标识与分支/工作区,互不串扰;
--resume <run-id>加载权威状态:从.omx/logs/autoresearch/<run-id>/manifest.json恢复运行;- 活跃运行锁:当仓库根目录的
.omx/state/autoresearch-state.json指向一个 active 运行(active: true且run_id非空)时,第二次启动会被拒绝。
参数解析与锁的实现在源码中可精确对应:
- 参数解析(含
--resume的两种写法--resume <id>与--resume=<id>)见 parseAutoresearchArgs; - 活跃运行锁的拒绝逻辑见 assertAutoresearchLockAvailable,错误信息形如
autoresearch_active_run_exists:<run-id>; - 测试用例 "rejects concurrent fresh runs via the repo-root active-run lock" 直接验证了该锁行为(见 runtime-parity-extra.test.ts)。
当前仓库的实际状态:由于命令已硬弃用,直接执行上述 CLI 会得到弃用提示与迁移指引(见 AUTORESEARCH_DEPRECATION_MESSAGE)。但契约本身依然是理解 runtime 状态的权威规范。
Mission / Sandbox 契约
目录约束
<mission-dir>必须满足:
- 位于一个 git 仓库内部(loadAutoresearchMissionContract 通过
git rev-parse --show-toplevel校验,并用路径相对关系防止逃逸); - 包含
mission.md与sandbox.md两个文件。
仓库中现成的完整示例见 missions/adaptive-sort-optimization/(使命为"优化自适应排序策略的加权成本分"),其 mission.md 描述目标与成功标准,sandbox.md 声明评估器与改动边界。
sandbox.md 的 YAML frontmatter
sandbox.md必须以 YAML frontmatter 开头,并定义评估器契约:
--- evaluator: command: python3 scripts/eval-adaptive-sort-optimization.py # 必填:评估命令 format: json # 必填:v1 只支持 json keep_policy: score_improvement # 可选:score_improvement | pass_only --- # 以下是 sandbox 正文(改动边界、允许/禁止的变更等)契约对 frontmatter 的校验非常严格(见 parseSandboxContract):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
evaluator.command | string | 是 | 评估命令,缺失时报evaluator.command is required |
evaluator.format | string | 是 | 必须是json,缺失或非 json 均报错 |
evaluator.keep_policy | string | 否 | 取值score_improvement(默认)或pass_only,非法值报错 |
评估器输出契约
评估器 stdout 必须输出 JSON,格式为:
{ "pass": true, "score": 0.85 }pass:必填,布尔值;score:可选,数值型。
解析逻辑见 parseEvaluatorResult:非 JSON、非对象、pass非布尔、score非数值都会被判定为契约错误;运行时评估(含超时与崩溃处理)见 runAutoresearchEvaluator,评估结果会被记录到latest-evaluator-result.json并追加进迭代台账(ledger)。
Runtime 模型
全新启动会创建的三类资源
全新启动(fresh launch)会创建:
- git 分支:
autoresearch/<mission-slug>/<run-tag>; - git worktree:
<repo>.omx-worktrees/autoresearch-<mission-slug>-<run-tag>(注:测试中实际路径形如.omx/worktrees/autoresearch-<slug>-<tag>,见 runtime-parity-extra.test.ts); - 仓库根目录运行工件:位于
.omx/logs/autoresearch/<run-id>/下。
run-tag 由 buildAutoresearchRunTag 生成(ISO 时间戳格式化),run-id 则由mission-slug与 run-tag 拼接而成(<mission-slug>-<run-tag 小写>,见 buildRunId)。
仓库根目录(repo-root)状态职责
| 文件 | 职责 |
|---|---|
.omx/state/autoresearch-state.json | 仅作为活跃运行指针/锁(active、run_id、worktree_path等) |
.omx/logs/autoresearch/<run-id>/manifest.json | 权威的每运行状态(schema_version、baseline/last_kept 提交、keep_policy、iteration 等) |
.omx/logs/autoresearch/<run-id>/candidate.json | 刚结束的 Codex 会话产出的候选交接物 |
.omx/logs/autoresearch/<run-id>/iteration-ledger.json | 持久化的迭代历史(entries 数组) |
.omx/logs/autoresearch/<run-id>/latest-evaluator-result.json | 最近一次评估器输出 |
这些文件与 manifest 结构在 AutoresearchRunManifest 与 prepareAutoresearchRuntime 中一一对应。注意 manifest 中每个路径字段(results_file、instructions_file、ledger_file等)都是绝对路径,这也是--resume能够脱离启动目录恢复状态的前提。
worktree 本地状态职责
results.tsv:TSV 格式的迭代结果表,表头固定为iteration commit pass score status description(见 AUTORESEARCH_RESULTS_HEADER);- 可选的评估器日志(如
run.log); - 这些运行时生成文件必须通过 worktree 本地的
.git/info/exclude排除在版本控制之外。
实现上,ensureRuntimeExcludes 会为results.tsv、run.log、node_modules、.omx/逐一写入 exclude 规则;isAllowedRuntimeDirtyLine 与 assertResetSafeWorktree 则在重置前校验"除这些白名单运行时文件外工作区必须干净",否则抛出autoresearch_reset_requires_clean_worktree:<path>:<冲突列表>。测试 "treats allowed runtime files as reset-safe and blocks unrelated dirt" 精确验证了这一行为(见 runtime-parity-extra.test.ts)。
另外,runtime 还会把仓库根目录的node_modules符号链接进 worktree(ensureAutoresearchWorktreeDependencies),避免在隔离工作区里重复安装依赖。
Candidate Artifact 候选产物
被启动的会话必须把candidate.json写到仓库根目录运行工件路径下,字段契约如下:
{ "status": "candidate", "candidate_commit": "abc1234", "base_commit": "def5678", "description": "short one-line summary", "notes": ["note1", "note2"], "created_at": "2026-09-09T01:00:00.000Z" }字段说明:
status:candidate | noop | abort | interrupted四选一;candidate_commit:字符串或null;base_commit:字符串(会话编辑前的基准提交);description:字符串(一句话摘要);notes:字符串数组;created_at:ISO 时间戳。
解析与严格校验分别见 parseAutoresearchCandidateArtifact(JSON 形状/类型校验)与 validateAutoresearchCandidate(git 完整性校验)。
完整性规则
status=candidate必须携带非空candidate_commit;candidate_commit必须在 git 中可解析,且与会话退出时 worktree 的HEAD提交一致——防止"声称提交了但实际没提交/提交了别的";base_commit必须在 git 中可解析,且等于监督者提供的last_kept_commit——防止候选基于过期基准开发。
这三条规则由 tryResolveGitCommit(git rev-parse --verify <ref>^{commit})与 HEAD 比对实现,任何一条不满足都会导致该迭代记为error并终结运行(failAutoresearchIteration)。
监督者对各 status 的处理
| status | 监督者行为 |
|---|---|
candidate | 运行评估器 → 分类 keep/discard/ambiguous/error → 更新 manifest/ledger/results → 若丢弃则重置 |
noop | 记录一次 noop 迭代并默认继续(不重置) |
abort | 停止运行,不重置 |
interrupted | 若工作区脏则停止等待人工介入;若干净则按 interrupted/noop 风格记录并继续 |
对应的分支实现见 recordNonEvaluatedCandidateStatus:interrupted且脏工作区时以failed终态停机(stop_reason 为interrupted dirty worktree requires operator intervention);noop/interrupted干净态都会更新 manifest 并重新生成下一轮指令文件。此外 countTrailingAutoresearchNoops 统计末尾连续 noop 次数,供上层决定是否继续推进。
Decision Policy 决策策略
决策的核心实现在 decideAutoresearchOutcome,规则如下:
- 基线行总是被记录:第 0 轮(
iteration=0,kind=baseline)在准备阶段就通过 seedBaseline 写入 results.tsv 与 ledger,并初始化last_kept_score; pass=false⇒ 丢弃(discard,reason:evaluator reported failure);- 评估器错误/崩溃 ⇒ 丢弃(
!evaluation || evaluation.status === 'error'时 discard,reason:evaluator error); keep_policy=score_improvement:仅当pass=true且score 优于上一次保留的 score 时才保留;pass=true但没有可比分数时记为ambiguous(reason:evaluator pass without comparable score)并丢弃;keep_policy=pass_only:任何pass=true的候选直接保留;- discard / ambiguous / error 路径必须重置到
last_kept_commit。
保留/重置的执行在 processAutoresearchCandidate:keep时更新last_kept_commit(worktree HEAD 全量哈希)与last_kept_score;否则调用 resetToLastKeptCommit 执行git reset --hard <last_kept_commit>。每次决策后都会:追加 results.tsv 行与 ledger 条目、写回 manifest、重写下一轮指令文件、更新模式状态中的最新评估信息。两个 keep policy 的差异在测试夹具中均有覆盖(makeContract 支持按 policy 生成 sandbox)。
Resume 语义
--resume <run-id>在以下情况必须失败并给出可操作的错误(错误码即诊断信息):
| 场景 | 错误码/行为 |
|---|---|
| manifest 缺失 | autoresearch_resume_manifest_missing:<run-id>(见 loadAutoresearchRunManifest) |
| 引用的 worktree 缺失 | autoresearch_resume_missing_worktree:<path> |
| worktree 在白名单运行时工件之外是脏的 | autoresearch_reset_requires_clean_worktree:... |
manifest 已是终态(非running) | autoresearch_resume_terminal_run:<run-id> |
恢复流程见 resumeAutoresearchRuntime:先校验锁与上述四个前置条件,再确保运行时 exclude 与 node_modules 链接就绪、校验工作区可重置,然后重新激活模式状态与活跃运行锁。成功的 resume 从最后保留的提交(last_kept_commit)和既有的结果历史(results.tsv / iteration-ledger.json)继续,不会重跑基线、也不会丢失已保留的成绩。测试 "resumes a running manifest and rejects missing worktrees" 覆盖了该路径(见 runtime-parity-extra.test.ts)。
Iteration Handoff Context 迭代交接上下文
每次启动的 worker 会话都会收到监督者写入的指令快照(由 writeInstructionsFile 生成,模板见 buildAutoresearchInstructions),内容包含:
- 当前迭代号(
iteration,即 manifest.iteration + 1); - 基线提交(
baseline_commit); - 最后保留的提交(
last_kept_commit); - 已知时附上最后保留的分数(
last_kept_score); - 上一轮迭代结果(
previous_iteration_outcome,格式decision:reason); - 有界长度的近期 ledger 摘要(默认最近 3 条,reason 截断 160 字符、description 截断 120 字符,见 formatAutoresearchInstructionSummary);
- keep policy;
- 附加的工具上下文(WorktreeToolContext,用于注入代码图指令)。
指令文件还会把 mission 内容、sandbox 政策正文、评估器契约完整内联,并明确要求"一次会话只做至多一次候选提交,写完候选产物 JSON 后退出,不要在会话内无限循环"。会话的使命目录(mission.md / sandbox.md)会先物化到 worktree 并提交,以保证后续重置安全性(materializeAutoresearchMissionToWorktree)。
验证目标与测试证据
契约结尾给出的六个 parity 验证目标,在仓库测试中均有对应覆盖(见 src/autoresearch/tests/ 与 contracts.test.ts、runtime.test.ts):
- fresh launch 创建彼此区分的 run-tagged 车道:run-tag/run-id 生成与独立 worktree 创建;
- repo-root 活跃运行锁拒绝并发启动:
autoresearch_active_run_exists测试; - candidate 交接产物驱动 keep/discard/reset 决策:
processAutoresearchCandidate全流程测试; - 被丢弃的候选重置到
last_kept_commit:resetToLastKeptCommit+assertResetSafeWorktree测试; --resume <run-id>重载权威 manifest/worktree 状态:resume 测试;- README/help/contracts 描述 thin-supervisor parity 循环:本文所依据的契约文档与 skills/autoresearch/SKILL.md 中的循环语义描述。
演进现状与迁移路径
需要特别说明的是:当前仓库中omx autoresearchCLI 命令已硬弃用(src/cli/autoresearch.ts),直接运行会报错并提示迁移(AUTORESEARCH_HELP)。可用的演进路径为:
- 用
$deep-interview --autoresearch澄清使命并生成规范工件:.omx/specs/autoresearch-{slug}/mission.md、sandbox.md、result.json(实现见 src/cli/autoresearch-guided.ts 与 src/cli/autoresearch-intake.ts,支持--topic/--evaluator/--keep-policy/--slug参数种子,parseInitArgs); - 用
$autoresearchskill 启动基于 native-hook 持久化的状态化研究循环,其完成判定以验证器证据为准(mission-validator-script或prompt-architect-artifact两种模式),不再依赖"连续 noop 计数"或 tmux 分屏启动(见 skills/autoresearch/SKILL.md)。
换句话说,本文剖析的 parity contract 描述的是这套机制的权威状态模型——无论命令面如何迭代,thin-supervisor 循环、git worktree 隔离、候选产物交接、评估器驱动决策这些核心语义,始终是 OmX 自动化研究能力的地基。
【免费下载链接】oh-my-codexOmX - Oh My codeX: Your codex is not alone. Add hooks, agent teams, HUDs, and so much more.项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-codex
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考