claude2codex 0.1.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/PATTERNS.md ADDED
@@ -0,0 +1,139 @@
1
+ # Contract Patterns
2
+
3
+ Field notes on writing Goal Contracts that get implemented correctly on the first try.
4
+
5
+ Everything here was distilled from a real build: seven Goal Contracts delivered through this bridge in two days (the Phase 2–4 features of this very repository — persistence, retry, concurrency, dependencies, the stall watchdog, cost estimation). All seven passed review without a single Delta Contract. These are the patterns that made that happen.
6
+
7
+ *[中文版](./PATTERNS.zh-CN.md)*
8
+
9
+ ## Anatomy of a contract that works
10
+
11
+ A real contract from this repo (Task 3.3, job dependency chaining), annotated:
12
+
13
+ ```markdown
14
+ ### Goal
15
+ codex_implement must support declaring a dependency on a previous job: the
16
+ dependent job starts automatically after the dependency succeeds, and fails
17
+ fast with a clear reason if the dependency fails.
18
+
19
+ 1. Schema: codex_implement gains an optional `depends_on: string` parameter...
20
+ 2. Submit-time validation: unknown job -> isError, no job created; ...
21
+ 3. Blocking semantics: ... blocked jobs do NOT consume concurrency slots ...
22
+ 4. Timing & events: the timeout clock starts when the job actually starts ...
23
+ 5. Persistence: ... on restart load, "blocked" jobs are marked interrupted ...
24
+ ```
25
+
26
+ What makes this work:
27
+
28
+ - **The first sentence is the acceptance test in prose.** Not "improve job orchestration" (a wish) but "starts automatically after the dependency succeeds, fails fast if it fails" (a behavior you can check).
29
+ - **Numbered specifics resolve every judgment call up front.** Does a blocked job consume a concurrency slot? When does the timeout clock start? What happens on restart? Each of these is a decision the implementer would otherwise make silently — and a coin-flip you'd catch (or miss) in review.
30
+ - **Edge semantics are stated, not implied.** "Unknown job → isError, *no job created*" pins both the error and the side-effect boundary.
31
+
32
+ The goal is not to write more words. It is to leave **zero open design decisions** that you would reject in review. If you would flag it in review, decide it in the contract.
33
+
34
+ ## Constraints: fence the blast radius
35
+
36
+ ```markdown
37
+ - Only modify mcp/src/jobs.ts, mcp/src/server.ts, plus new test files under mcp/test/.
38
+ - Do not modify: contracts.ts, codex-client.ts, log.ts, store.ts, config.ts, docs/, README*.
39
+ - No new runtime dependencies. Tool schemas may only be extended additively.
40
+ - Persisted format must stay backward compatible: old files without the new field must load.
41
+ - The existing N tests keep passing; only minimal adjustments are allowed.
42
+ ```
43
+
44
+ Patterns that earn their place:
45
+
46
+ - **An explicit allow-list and an explicit deny-list.** The allow-list scopes the diff you will have to review. The deny-list protects load-bearing files. Review then starts with a 5-second `git status` check against both.
47
+ - **"Additively extendable" for any public surface** (schemas, persisted formats, APIs). This one line prevents silent breaking changes.
48
+ - **Name the exact current test count** ("the existing 29 tests keep passing"). It makes "don't break what works" checkable, and drift in the number is itself a review signal.
49
+ - **Expect principled violations.** In this repo's run, Codex once modified two existing mock files that were technically outside the allow-list — because a new default (retries on) had changed what the old mocks meant. That was the *correct* engineering call. Judge boundary crossings by whether the contract's success conditions forced them; a good handoff will volunteer the reason.
50
+
51
+ ## Success Conditions: make the machine do the judging
52
+
53
+ The single most important rule: **at least one condition is a command whose exit code decides.** Everything else builds on that.
54
+
55
+ Verification tricks that proved decisive, all lifted from this repo's test suites:
56
+
57
+ | To prove... | Do this |
58
+ |---|---|
59
+ | "No job/record was created on rejection" | Count files in the state directory before and after; assert equality. |
60
+ | "The prompt actually delivered contains X" | Make the mock *reject the request* when X is absent (`EXPECT_*` env vars). Success of the job then *is* the proof. |
61
+ | "No process was ever spawned" | Assert on two independent channels: no spawn event in the structured log *and* no attempt/thread entries in the transcript. |
62
+ | "File contents are never inlined into the prompt" | Write a marker string into the file; assert the prompt does not contain it. |
63
+ | "B starts only after A finishes" | Assert event *ordering* in the progress stream, not just final states. |
64
+ | "Timeout counts from dequeue, not enqueue" | Set total elapsed > timeout with queueing; completion itself proves the clock's start point. |
65
+ | "The timing-sensitive test isn't flaky" | Run it under `bun test --rerun-each 3` (or equivalent) before accepting it. |
66
+
67
+ And the meta-rule for the handoff: **require it in the contract.** Every contract here ends with:
68
+
69
+ ```markdown
70
+ - [ ] The final handoff lists: Changed Files, Validation (commands + output),
71
+ each Success Condition with its verification result, and Risks & Deviations.
72
+ ```
73
+
74
+ A missing or incomplete handoff is itself a review failure — you never have to argue about it, because it was a success condition.
75
+
76
+ ## The objective budget: your success conditions have a character limit
77
+
78
+ The contract you send and the objective the goal loop audits are **not the same string**. `codex_implement` renders a compact objective from your `goal` plus every `success_condition` and sets it via `thread/goal/set`. That objective — not the full contract prompt — is what Codex's `/goal` loop checks before declaring the goal achieved. Constraints and context files never reach it; they live only in the turn prompt.
79
+
80
+ It has a hard budget: `GOAL_OBJECTIVE_MAX`, default **2000 characters**, of which ~213 are fixed rendering boilerplate. The remaining ~1787 are your goal text plus the concatenation of every success condition.
81
+
82
+ Two consequences:
83
+
84
+ - **Prose burns the budget fast.** A ten-condition contract of ordinary English sentences lands around 1700–2000 characters. The contract that added this very check measured 1987/2000 on its first draft — 13 characters of margin, entirely by accident.
85
+ - **Measure before you send.** `codex_estimate` reports `objective_chars`, `objective_max_chars`, and `objective_over_limit` without creating a job. Over-limit calls to `codex_implement` are rejected at submit time — no job, no process, no tokens spent — with the actual count in the error.
86
+
87
+ Write success conditions as assertions, not paragraphs:
88
+
89
+ ```markdown
90
+ Bad (124 chars): The implementation should make sure that whenever a contract
91
+ exceeds the configured limit, the tool refuses to create a job.
92
+ Good (76 chars): Over-limit contracts return isError and create no job (state dir unchanged).
93
+ ```
94
+
95
+ If a task genuinely needs a longer objective, raise `GOAL_OBJECTIVE_MAX` deliberately. The usual right answer is that ten crisp conditions beat six verbose ones — and the crisp ones review better anyway.
96
+
97
+ ## Review: never trust, always re-run
98
+
99
+ The handoff says `bun test` passed. Run `bun test` anyway. In this repo's run every handoff happened to be truthful — and that is exactly what you can't assume, because the day one isn't, the re-run is your only defense. The review loop that worked:
100
+
101
+ 1. `git status` against the allow/deny lists (5 seconds).
102
+ 2. Read the diff — for design, not just correctness. (Two of the best findings here were *positive*: a fairness fix and a stall-boundary refinement the contract never asked for.)
103
+ 3. Re-run every verification command yourself, from a clean shell.
104
+ 4. Check the handoff's Risks & Deviations against what the diff actually shows. "None" plus an undeclared deviation is a worse sign than a declared one. A handoff that says "P90 uses the nearest-rank method" unprompted is a good sign.
105
+
106
+ ## Delta Contracts: scope to the failure
107
+
108
+ When review fails, do not renegotiate the task. Send back only:
109
+
110
+ ```markdown
111
+ ### Findings
112
+ - store.ts:41 — interrupted jobs keep their stale endedAt; restart test fails.
113
+
114
+ ### Failed Success Conditions
115
+ - [ ] Persistence round-trip test passes.
116
+
117
+ ### Constraints
118
+ - Original constraints still apply. Fix only the findings above; do not touch work that passed.
119
+ ```
120
+
121
+ The thread (and its goal) resumes — Codex retains full context of its own implementation, so the fix is surgical. This repo's run needed zero Delta Contracts across seven tasks; the honest attribution is contract precision up front, which is cheaper than any rework loop.
122
+
123
+ ## Calibration numbers (one local data point)
124
+
125
+ From the seven implement jobs that built Phases 2–4 (TypeScript, ~40–440 line diffs each, `reasoning_effort: high`):
126
+
127
+ - **Tokens per job:** 51k–128k (median ≈ 87k). `codex_estimate` now surfaces your own local numbers — prefer those.
128
+ - **Wall time per job:** 5–15 minutes when healthy; two jobs stalled mid-turn for 10–16 minutes (upstream CLI issue) and self-recovered.
129
+ - **Timeout:** the 30-minute default absorbed both stalls. If you tighten it, watch `seconds_since_activity` (stall watchdog) before concluding a job is dead — reasoning pauses and stalls look identical from outside.
130
+ - **Effort:** `high` produced above-contract judgment calls (fairness fixes, boundary refinements) that default effort had not. For contracts whose edge semantics matter, it paid for itself.
131
+
132
+ ## Anti-patterns
133
+
134
+ - **The vision goal.** "Make the server production-ready." Codex will decide what that means; you will disagree in review.
135
+ - **The unverifiable condition.** "Code is clean and well-tested." If a machine can't decide it, it's a review note, not a success condition.
136
+ - **The unfenced diff.** No file allow-list → the diff sprawls → review cost explodes → subtle regressions hide in noise.
137
+ - **The implicit edge.** Every "what happens if X" you leave open is decided by the implementer, silently, against your review checklist.
138
+ - **The trusted handoff.** Accepting "all tests pass" without re-running is not review; it's hope with extra steps.
139
+ - **The mega-contract.** One contract per reviewable increment. Seven small contracts with clean handoffs beat one heroic contract every time — and the rework loop stays surgical when something does fail.
@@ -0,0 +1,138 @@
1
+ # 契约模式
2
+
3
+ 关于如何写出"一次过审"的 Goal Contract 的实战笔记。
4
+
5
+ 本文的每一条都来自一次真实的构建:两天内通过这座桥交付了七份 Goal Contract(正是本仓库自己的 Phase 2–4 功能——持久化、重试、并发、依赖链、停滞看门狗、成本预估)。七份合同全部一次通过审查,没有发出过一份 Delta Contract。下面就是让这件事发生的模式。
6
+
7
+ *[English version](./PATTERNS.md)*
8
+
9
+ ## 一份有效合同的解剖
10
+
11
+ 本仓库的真实合同(Task 3.3,任务依赖链),带注解:
12
+
13
+ ```markdown
14
+ ### Goal
15
+ codex_implement 必须支持声明对先前 job 的依赖:被依赖的 job 成功后,
16
+ 依赖它的 job 自动启动;失败则依赖方快速失败并附明确原因。
17
+
18
+ 1. Schema:codex_implement 新增可选参数 `depends_on: string` ……
19
+ 2. 提交时校验:未知 job -> isError,不创建 job;……
20
+ 3. 阻塞语义:…… blocked 状态的 job 不占用并发槽位 ……
21
+ 4. 计时与事件:总超时从 job 实际启动时才开始计 ……
22
+ 5. 持久化:…… 重启加载时 "blocked" 状态标记为 interrupted ……
23
+ ```
24
+
25
+ 它有效的原因:
26
+
27
+ - **第一句话就是验收测试的散文版。** 不是"改进任务编排"(愿望),而是"依赖成功后自动启动、失败则快速失败"(可以核对的行为)。
28
+ - **编号条目预先解决所有需要判断的问题。** blocked 的 job 占不占并发槽位?超时从什么时候开始计?重启后怎么办?每一个都是实现者原本会默默替你做的决定——一次你只能在审查时才能抓到(或漏掉)的掷硬币。
29
+ - **边界语义写明,而非暗示。** "未知 job → isError,*不创建 job*"同时锁定了错误行为和副作用边界。
30
+
31
+ 目标不是把合同写长,而是**留下零个你会在审查时打回的开放设计决策**。凡是你会在审查里挑的刺,就在合同里先定下来。
32
+
33
+ ## Constraints:圈定爆炸半径
34
+
35
+ ```markdown
36
+ - 只修改 mcp/src/jobs.ts、mcp/src/server.ts,及 mcp/test/ 下的新测试文件。
37
+ - Do not modify:contracts.ts、codex-client.ts、log.ts、store.ts、config.ts、docs/、README*。
38
+ - 不新增运行时依赖。工具 schema 只能增量扩展。
39
+ - 持久化格式必须向后兼容:没有新字段的旧文件必须能正常加载。
40
+ - 现有 N 个测试保持通过;只允许最小必要调整。
41
+ ```
42
+
43
+ 值得保留的模式:
44
+
45
+ - **显式的允许清单 + 显式的禁止清单。** 允许清单圈定你将要审查的 diff 范围;禁止清单保护承重文件。审查的第一步就是花 5 秒把 `git status` 对照这两张清单。
46
+ - **对一切公共表面(schema、持久化格式、API)要求"只许增量扩展"。** 这一行防住所有静默的破坏性变更。
47
+ - **写明当前测试的确切数量**("现有 29 个测试保持通过")。它让"别弄坏已有的东西"变得可核验,数字的漂移本身就是审查信号。
48
+ - **预期有原则的越界。** 在本仓库的实战中,Codex 有一次修改了两个严格来说在允许清单之外的旧 mock 文件——因为一个新默认值(重试开启)改变了旧 mock 的语义。那是*正确的*工程判断。裁量越界时看它是否被合同的 Success Conditions 逼出来;好的 handoff 会主动说明理由。
49
+
50
+ ## Success Conditions:让机器来当裁判
51
+
52
+ 最重要的一条规则:**至少有一个条件是由退出码说了算的命令。** 其他一切都建立在这之上。
53
+
54
+ 以下验证技巧全部出自本仓库的测试套件,并且都在关键时刻起了作用:
55
+
56
+ | 要证明…… | 就这样做 |
57
+ |---|---|
58
+ | "拒绝时没有创建任何 job/记录" | 调用前后数状态目录里的文件,断言相等。 |
59
+ | "实际送达的 prompt 里包含 X" | 让 mock 在缺少 X 时*拒绝请求*(`EXPECT_*` 环境变量)。job 能跑成功本身就是证明。 |
60
+ | "从未 spawn 过进程" | 用两条独立通道断言:结构化日志里无 spawn 事件,*且* transcript 里无 attempt/thread 记录。 |
61
+ | "文件内容从未被内联进 prompt" | 往文件里写一个标记串,断言 prompt 里没有它。 |
62
+ | "B 只在 A 结束后才启动" | 断言 progress 事件流的*顺序*,而不只是最终状态。 |
63
+ | "超时从出队开始计,而不是入队" | 让总耗时超过配置的超时并带排队;能跑完本身就证明了计时起点。 |
64
+ | "时序敏感的测试不 flaky" | 接受之前先用 `bun test --rerun-each 3`(或等价手段)压一遍。 |
65
+
66
+ 还有关于 handoff 的元规则:**把它写进合同。** 这里的每份合同都以这一条收尾:
67
+
68
+ ```markdown
69
+ - [ ] Final handoff 列出:Changed Files、Validation(命令 + 输出)、
70
+ 每条 Success Condition 的核验结果、Risks & Deviations。
71
+ ```
72
+
73
+ 缺失或不完整的 handoff 本身就是审查失败——你永远不需要为此争论,因为它就是一条成功条件。
74
+
75
+ ## objective 预算:你的 Success Conditions 有字符上限
76
+
77
+ 你发出去的合同,和 goal loop 实际审的 objective,**不是同一个字符串**。`codex_implement` 会从 `goal` 加上每一条 `success_condition` 渲染出一个精简的 objective,通过 `thread/goal/set` 设进去。Codex 的 `/goal` 循环在宣布目标达成前,审的是这个 objective,而不是完整的合同 prompt。Constraints 和 context files 根本进不去 —— 它们只存在于 turn prompt 里。
78
+
79
+ 它有一条硬预算:`GOAL_OBJECTIVE_MAX`,默认 **2000 字符**,其中约 213 是固定的渲染样板。剩下约 1787 字符由你的 goal 正文和所有 success conditions 拼接而成。
80
+
81
+ 两个后果:
82
+
83
+ - **散文最烧预算。** 十条普通英文句子写成的 success conditions,落点大约在 1700–2000 字符。加入这条检查的那份合同,初稿实测 1987/2000 —— 只剩 13 字符余量,纯属侥幸。
84
+ - **发之前先量。** `codex_estimate` 会返回 `objective_chars`、`objective_max_chars`、`objective_over_limit`,且不创建 job。超限的 `codex_implement` 调用会在提交时被拒 —— 不建 job、不起进程、不烧 token —— 错误里直接给出实际字符数。
85
+
86
+ Success conditions 要写成断言,不要写成段落:
87
+
88
+ ```markdown
89
+ 差(124 字符):The implementation should make sure that whenever a contract
90
+ exceeds the configured limit, the tool refuses to create a job.
91
+ 好( 76 字符):Over-limit contracts return isError and create no job (state dir unchanged).
92
+ ```
93
+
94
+ 如果某个任务确实需要更长的 objective,那就有意识地调高 `GOAL_OBJECTIVE_MAX`。但通常正确的答案是:十条精悍的条件胜过六条啰嗦的 —— 而且精悍的那种审查起来也更省事。
95
+
96
+ ## 审查:永不轻信,永远重跑
97
+
98
+ handoff 说 `bun test` 过了。你还是要自己跑一遍 `bun test`。在本仓库的实战中,每一份 handoff 碰巧都是诚实的——而这恰恰是你不能假设的事,因为哪天有一份不诚实,你的重跑就是唯一的防线。行之有效的审查循环:
99
+
100
+ 1. `git status` 对照允许/禁止清单(5 秒)。
101
+ 2. 读 diff——不止看对错,还看设计。(这里最好的两个发现都是*正面的*:一次公平性修复和一次停滞边界的精化,都是合同没要求的。)
102
+ 3. 亲自从干净的 shell 重跑每一条验证命令。
103
+ 4. 把 handoff 的 Risks & Deviations 和 diff 的实际内容对照。"None" 加上一个未声明的偏差,比声明了偏差更危险。主动写出"P90 用的是 nearest-rank 方法"的 handoff 是好信号。
104
+
105
+ ## Delta Contract:只圈定失败项
106
+
107
+ 审查失败时,不要重新谈判整个任务。只发回:
108
+
109
+ ```markdown
110
+ ### Findings
111
+ - store.ts:41 — interrupted 的 job 保留了过期的 endedAt;重启测试失败。
112
+
113
+ ### Failed Success Conditions
114
+ - [ ] 持久化往返测试通过。
115
+
116
+ ### Constraints
117
+ - 原有约束继续适用。只修复上述发现;不要碰已通过的部分。
118
+ ```
119
+
120
+ 线程(连同它的 goal)会被恢复——Codex 保有它自己实现的完整上下文,所以修复是外科手术式的。本仓库的七个任务零 Delta Contract;诚实的归因是前期合同写得足够精确,而这比任何返工循环都便宜。
121
+
122
+ ## 校准数字(一个本地数据点)
123
+
124
+ 来自构建 Phase 2–4 的七个 implement job(TypeScript,单个 diff 约 40–440 行,`reasoning_effort: high`):
125
+
126
+ - **单任务 token:** 51k–128k(中位数 ≈ 87k)。`codex_estimate` 现在能给出你自己机器上的数字——优先用那个。
127
+ - **单任务耗时:** 健康时 5–15 分钟;有两个 job 在 turn 中途停滞了 10–16 分钟(上游 CLI 问题)后自行恢复。
128
+ - **超时:** 30 分钟的默认值兜住了两次停滞。如果你要收紧它,先看停滞看门狗的 `seconds_since_activity` 再判断 job 是否死了——从外面看,深度推理的暂停和真正的停滞长得一模一样。
129
+ - **Effort:** `high` 产出了超出合同要求的判断(公平性修复、边界精化),默认档没有。对边界语义重要的合同,它物有所值。
130
+
131
+ ## 反模式
132
+
133
+ - **愿景式目标。** "把 server 做到 production-ready。" Codex 会自己决定这是什么意思;你会在审查时不同意。
134
+ - **不可机验的条件。** "代码整洁、测试充分。" 机器判不了的,就是审查备注,不是成功条件。
135
+ - **无围栏的 diff。** 没有文件允许清单 → diff 蔓延 → 审查成本爆炸 → 细微回归藏进噪音。
136
+ - **隐式边界。** 你留下的每一个"如果 X 会怎样",都会被实现者默默决定——并且是对着你的审查清单反着来。
137
+ - **轻信 handoff。** 不重跑就接受"所有测试通过",那不是审查,是多了几个步骤的祈祷。
138
+ - **巨型合同。** 一份合同对应一个可审查的增量。七份小合同加干净的 handoff,永远胜过一份史诗级合同——而且真出问题时,返工循环还能保持外科手术式。
package/README.md CHANGED
@@ -1,62 +1,182 @@
1
- # c2c-codex — Claude↔Codex Contract Bridge (MCP server)
1
+ # claude2codex
2
2
 
3
- *[中文](./README.zh-CN.md)*
3
+ An MCP server that lets Claude Code delegate implementation work to OpenAI Codex through structured contracts.
4
4
 
5
- Claude Code is the **architect/reviewer** (see `../CLAUDE.md`); Codex is the **implementer** (see `../AGENTS.md`). This MCP server is the courier between them: it turns Goal/Delta Contracts into Codex runs and returns the structured handoff for Claude to review. It is **language-agnostic** — all verification commands come from the contract's Success Conditions, never from this server.
5
+ *[中文版](./README.zh-CN.md)*
6
6
 
7
- ## How it works
7
+ ## Demo
8
8
 
9
- Each job spawns `codex app-server` (Codex's JSON-RPC interface, stdio/JSONL) and drives it:
9
+ One real contract round-trip, recorded live: Claude drafts the Goal Contract, `codex_estimate` prices it, Codex implements under its goal loop while `codex_status` streams progress, and Claude independently re-verifies the handoff.
10
10
 
11
+ ![c2c demo — a full Claude→Codex contract round-trip](./demo/demo.gif)
12
+
13
+ *Real Codex run (13k tokens, 50s), waits compressed. Replay in your terminal: `asciinema play demo/demo.cast`*
14
+
15
+ ## The Idea
16
+
17
+ Software development has distinct roles: **planning** what to build, **building** it, and **reviewing** the result. This project splits those roles between two AI agents:
18
+
19
+ - **Claude Code** — the architect and reviewer. Plans the work, writes specifications, reviews results.
20
+ - **OpenAI Codex** — the implementer. Receives specifications, writes code, runs tests, reports back.
21
+
22
+ You (the user) are the **commander** — you decide what to build and give final approval. Claude drafts the plan, Codex executes it, Claude verifies the output.
23
+
24
+ ```mermaid
25
+ flowchart LR
26
+ User -->|decides what to build| Claude
27
+ Claude -->|Goal Contract| Codex
28
+ Codex -->|structured handoff| Claude
29
+ Claude -->|review verdict| User
30
+ Claude -.->|Delta Contract if review fails| Codex
31
+ ```
32
+
33
+ ## What is a Goal Contract?
34
+
35
+ A Goal Contract is a structured specification that tells Codex *exactly* what to build. It has three parts:
36
+
37
+ | Section | Purpose |
38
+ |---------|---------|
39
+ | **Goal** | What the code must do when this task is done. |
40
+ | **Constraints** | Boundaries: which files to touch, patterns to follow, things *not* to modify. |
41
+ | **Success Conditions** | Checkable criteria that prove the goal is met. At least one must be a runnable test or command. |
42
+
43
+ Example:
44
+
45
+ ```markdown
46
+ ### Goal
47
+ Add a /health endpoint that returns 200 OK with the server version.
48
+
49
+ ### Constraints
50
+ - Only modify src/routes.ts and src/routes.test.ts.
51
+ - Do not modify any existing endpoints.
52
+ - Follow the existing route registration pattern.
53
+
54
+ ### Success Conditions
55
+ - [ ] GET /health returns 200 with JSON body {"version": "<package.json version>"}.
56
+ - [ ] `npm test` passes including a new test for the endpoint.
57
+ - [ ] No other routes are affected.
11
58
  ```
12
- initialize
13
- → thread/start (or thread/resume for rework)
14
- → thread/goal/set objective = the Goal Contract, distilled ← this is /goal
15
- → turn/start input = the full rendered contract
16
- → ... Codex's goal-continuation loop runs turns until the goal is achieved ...
17
- → job done when goal status is terminal (complete / budget_limited),
18
- or the thread goes quiet after a turn with the goal still active
59
+
60
+ **Why structure it this way?** Codex works best with unambiguous, verifiable instructions. Vague requests produce vague results. The contract format forces clarity: what to do, what not to do, and how to prove it worked.
61
+
62
+ For a deeper, field-tested guide — contract anatomy, verification tricks, review discipline, calibration numbers, and anti-patterns, all distilled from building this repo's own features through the bridge — see **[PATTERNS.md](./PATTERNS.md)**.
63
+
64
+ ## What is a Delta Contract?
65
+
66
+ When Claude reviews Codex's output and finds problems, it doesn't start over — it sends a **Delta Contract** (a rework order) scoped to *only* what failed:
67
+
68
+ | Section | Purpose |
69
+ |---------|---------|
70
+ | **Findings** | What is wrong, with file/line references. |
71
+ | **Failed Conditions** | Which Success Conditions from the original contract did not pass. |
72
+
73
+ Codex resumes the same thread (keeping all context from the first attempt) and fixes only the identified issues.
74
+
75
+ ## Full Workflow
76
+
77
+ ```mermaid
78
+ flowchart TD
79
+ A[User decides what to build] --> B[Claude drafts Goal Contract]
80
+ B --> C{User approves?}
81
+ C -->|yes| D[Codex implements]
82
+ C -->|no| B
83
+ D --> E[Claude reviews output]
84
+ E --> F{All conditions met?}
85
+ F -->|yes| G[User gives final approval]
86
+ F -->|no| H[Claude drafts Delta Contract]
87
+ H --> D
88
+ G --> I[Done - update docs]
19
89
  ```
20
90
 
21
- Setting the thread goal is the programmatic equivalent of the `/goal` slash command in the Codex TUI: Codex audits its own work against the objective after each turn and keeps going ("Goal achieved" / "Goal unmet") until it passes or hits the token budget.
91
+ ## Three-Layer Prompt Architecture
22
92
 
23
- ## Tools
93
+ The prompt Codex works from is assembled from three layers, but only two of them come from claude2codex:
24
94
 
25
- | Tool | Purpose |
26
- |---|---|
27
- | `codex_implement` | Start a job from a Goal Contract (`goal`, `constraints[]`, `success_conditions[]`, optional `token_budget`, `cwd`). Returns `job_id` immediately. |
28
- | `codex_status` | Poll a job: state, thread id, goal status/tokens, turn count, transcript tail. |
29
- | `codex_result` | Fetch a finished job: final message + parsed handoff (Changed Files / Validation / Success Conditions / Risks & Deviations). A missing section ⇒ `handoff.valid: false` — per CLAUDE.md that is itself a review failure. |
30
- | `codex_rework` | Resume the same Codex thread with a Delta Contract (`findings[]`, `failed_conditions[]`). The existing thread goal re-engages. |
95
+ 1. **Protocol layer** (embedded in the MCP server) — universal rules: how to self-verify work, how to format the handoff, how to handle rework. These never change regardless of project.
31
96
 
32
- ## Configuration (env vars)
97
+ 2. **Project layer** (`AGENTS.md`) — project-specific coding conventions, toolchain instructions, architectural constraints. **Loaded by Codex itself, not by this server.** Codex discovers `AGENTS.md` files across the working directory's repository tree (plus `AGENTS.override.md`) and places them in its instructions layer, subject to its own `project_doc_max_bytes` budget. claude2codex used to inject the file a second time and no longer does.
33
98
 
34
- | Var | Default | Meaning |
35
- |---|---|---|
36
- | `CODEX_BIN` | `codex` | Codex executable |
37
- | `CODEX_ARGS` | `app-server` | Args (space-separated) |
38
- | `CODEX_CWD` | server cwd | Default working directory for jobs |
39
- | `CODEX_MODEL` | (codex default) | Model override passed to `thread/start` |
40
- | `CODEX_APPROVAL_POLICY` | `never` | Codex approval policy (autonomous worker) |
41
- | `CODEX_PERMISSIONS` | (unset) | Codex permissions profile passthrough |
42
- | `CODEX_JOB_TIMEOUT_MS` | `1800000` | Hard cap per job (30 min) |
43
- | `CODEX_QUIET_MS` | `30000` | Quiet window after a turn before declaring a still-active goal finished |
44
- | `GOAL_OBJECTIVE_MAX` | `2000` | Max length of the `thread/goal/set` objective string |
99
+ 3. **Task layer** (the Goal/Delta Contract itself) — the specific work to be done this time.
45
100
 
46
- ## Run / test
101
+ This separation means the MCP server works out of the box (layer 1 is always there), inherits whatever project context Codex already loads (layer 2), and carries the unique task specification (layer 3).
102
+
103
+ Note that the contract prompt and the **thread-goal objective** are different strings. The objective — rendered from `goal` plus every `success_condition` — is what Codex's `/goal` loop audits before declaring the goal achieved, and it has its own `GOAL_OBJECTIVE_MAX` budget. See [PATTERNS.md](PATTERNS.md#the-objective-budget-your-success-conditions-have-a-character-limit).
104
+
105
+ ## Installation
106
+
107
+ Requires [Codex CLI](https://github.com/openai/codex) and Node.js 18+.
47
108
 
48
109
  ```sh
49
- bun install
50
- bun test # e2e against test/mock-codex.ts (no real Codex needed)
51
- bunx tsc --noEmit # typecheck
110
+ npx claude2codex
52
111
  ```
53
112
 
54
- Registered for Claude Code in `../.mcp.json`. The server itself runs on Bun (Node ≥ 22.18 also works — the TS is erasable-syntax only).
113
+ ### MCP Configuration
114
+
115
+ Add to your Claude Code MCP settings:
116
+
117
+ ```json
118
+ {
119
+ "mcpServers": {
120
+ "codex": {
121
+ "command": "npx",
122
+ "args": ["-y", "claude2codex"]
123
+ }
124
+ }
125
+ }
126
+ ```
127
+
128
+ ## Tools Provided
129
+
130
+ | Tool | Description |
131
+ |------|-------------|
132
+ | `codex_implement` | Start a Codex job from a Goal Contract. Supports `context_files` (read-first references, validated to exist) and `depends_on` (start only after a prior job succeeds). Returns a job ID immediately. |
133
+ | `codex_status` | Check job progress: state, queue position, dependency, turns, goal status, token usage, time since last activity, transcript. |
134
+ | `codex_result` | Fetch the finished job's structured handoff. |
135
+ | `codex_rework` | Resume the Codex thread with a Delta Contract (also accepts `context_files`). |
136
+ | `codex_estimate` | Read-only pre-job cost estimate: rendered-prompt size, thread-goal objective size against `GOAL_OBJECTIVE_MAX`, plus token statistics from your local completed jobs. |
137
+ | `codex_config` | Read-only view of Codex's current model, version, and settings. |
138
+
139
+ Jobs are persisted (`C2C_STATE_DIR`), so status, results, and rework survive server restarts. Jobs beyond the concurrency cap queue FIFO; a stall watchdog reports when a running job stops making progress. See [PATTERNS.md](./PATTERNS.md) for field-tested guidance on writing contracts that pass review on the first try.
140
+
141
+ ## How the Goal Loop Works
142
+
143
+ Under the hood, each job:
144
+
145
+ 1. Spawns a `codex app-server` process (Codex's JSON-RPC interface)
146
+ 2. Starts (or resumes) a persisted thread
147
+ 3. Sets a **thread goal** — the programmatic equivalent of Codex's `/goal` command
148
+ 4. Sends the full contract as input
149
+
150
+ Codex then enters its goal-continuation loop: after each turn, it checks "did I achieve the goal?" If not, it keeps going. The job finishes when the goal reaches a terminal state (`complete` or `budget_limited`) or the thread goes quiet.
151
+
152
+ ## Environment Variables
153
+
154
+ | Variable | Default | Description |
155
+ |----------|---------|-------------|
156
+ | `CODEX_BIN` | `codex` | Codex executable to launch |
157
+ | `CODEX_ARGS` | `app-server` | Space-separated Codex arguments |
158
+ | `CODEX_CWD` | Current directory | Default working directory for jobs |
159
+ | `CODEX_MODEL` | Codex default | Model override |
160
+ | `CODEX_APPROVAL_POLICY` | `never` | Approval policy (autonomous by default) |
161
+ | `CODEX_PERMISSIONS` | Unset | Permissions profile passed to Codex |
162
+ | `CODEX_JOB_TIMEOUT_MS` | `1800000` | Maximum job duration (30 min) |
163
+ | `CODEX_QUIET_MS` | `30000` | Quiet period before treating an active goal as finished |
164
+ | `GOAL_OBJECTIVE_MAX` | `2000` | Maximum rendered goal-objective length; `codex_implement` rejects over-limit contracts at submit time |
165
+ | `C2C_STATE_DIR` | `~/.claude2codex/jobs` | Persistent job registry (atomic per-job JSON files) |
166
+ | `C2C_LOG_LEVEL` | `info` | Structured JSON logs on stderr: `silent`, `error`, `info`, `debug` |
167
+ | `C2C_RETRIES` | `1` | Automatic retries for process failures before the first turn starts |
168
+ | `C2C_MAX_CONCURRENT` | `2` | Max simultaneously active Codex jobs; overflow queues FIFO |
169
+ | `C2C_STALL_WARN_MS` | `120000` | Stall watchdog threshold; emits stalled/resumed events; `0` disables |
170
+
171
+ ## Development
172
+
173
+ ```sh
174
+ cd mcp
175
+ bun install
176
+ bun test # e2e tests against a mock codex (no real API calls)
177
+ npm run build # produces dist/server.js
178
+ ```
55
179
 
56
- ## Status / caveats
180
+ ## License
57
181
 
58
- - **Verified live** against `codex` 0.144.6 (2026-07-19): `test/live-smoke.ts` drove a real contract through the MCP server — `thread/goal/set` accepted, goal tracked `tokensUsed` and went `active → complete`, Codex self-verified the success condition, and the structured handoff parsed valid. Also covered by `bun test` against `test/mock-codex.ts` (no real Codex or model spend needed).
59
- - Requires a reasonably current Codex CLI (`npm i -g @openai/codex@latest`). Note: a stale install can fail with an instant `zsh: killed` after a macOS update — reinstalling fixes it.
60
- - If Codex's goals feature is unavailable in a build ("goals feature is disabled"), `thread/goal/set` failure degrades the job gracefully to single-turn mode and notes it in the transcript.
61
- - Goals require a persisted thread; `thread/start` defaults are used (no ephemeral threads).
62
- - Server→client requests (approvals) are declined automatically — jobs run with `approvalPolicy: never`; tune `CODEX_PERMISSIONS` if Codex needs broader sandbox rights.
182
+ MIT