Choosing and Combining Claude and Codex: A Real Side-by-Side on the Same Task, a Write-One-Review-One Mixed Workflow
Run the same task through both Codex and Claude Code, compare them across four dimensions — how you brief them, approval, verification, and cost — then combine the two tools into a daily write-one-review-one workflow.
Today's Goals
- Run the same task on both Codex and Claude Code, and record comparable data across four dimensions
- Explain how the two coding agents differ in project context, approval model, and verification habits, and justify a choice to a team
- Set up a write-one-review-one mixed workflow, and know when it isn't worth it
Four days in, you know how the OpenAI contractor works. Today we invite the other firm's contractor into the same room, hand over the same job, and watch both of them work. There is only one problem to solve: when someone asks which one your team should use, you can give reasons they can verify rather than saying it feels good to you. Once you have read this and finished the work, scroll back to the top and tick off the three goals.
Plain-Language Walkthrough
Why measure for yourself instead of reading a leaderboard
The two contractors come from different firms and you want to know which suits your team. The lazy route is to read a leaderboard — but a leaderboard measures solving a standardized problem, while your team's work is changing an endpoint inside a repository with years of history, and the gap between the two is wide enough that the leaderboard is essentially uninformative. Worse, a leaderboard reports one score, while what you actually care about day to day is four very concrete things:
| Dimension | The question you are really asking |
|---|---|
| Briefing | How much do I have to write, and how much context prepare, before it starts on the right work |
| Approval | How many times does it interrupt me, and what for each time |
| Verification | Does it run the tests itself before saying it is done, or say it is done and leave the running to me |
| Cost | How much time, how many tokens, how much money |
Those four have one thing in common: all of them can be measured in your own repository on your own task. So the last day of this course does not give you a conclusion; it gives you a way to measure. The task is the one we have used for five days: add input validation and matching unit tests to a TODO API written with Express or FastAPI — the same task D3 through D5 of the companion Claude course does with Claude Code, so readers of both courses can compare data directly.
Set the rules before measuring, or the data will not be comparable: the same repository starting point (the same commit), the same requirement text, the same content in each side's project instruction file, default permissions on both, and both asked to run the tests before reporting. Those rules are in the lab's record template, and you just fill it in.
The same task through Codex: AGENTS.md, workspace-write, /review, end to end
You already know this side well, and stringing the first four days together gives the whole flow.
Briefing: put the AGENTS.md you wrote on D1 in the project root (validation with zod, tests with vitest, the error response shape), then give codex a requirement:
Add input validation to POST /todos (title a non-empty string of 1-200 characters, done
optional and boolean, a failure returning 400 with { error: string }), and add unit tests
for the POST, GET, and DELETE routes. Use the validation library and test framework from
AGENTS.md. Run pnpm test afterwards and, once green, report in one sentence which files
you changed.Note the length of that requirement and the length of AGENTS.md — that is your briefing cost.
Approval: the default Auto (workspace-write plus on-request). Reading files, editing files, and running pnpm test are all inside the sandbox and raise nothing; if it decides to install a new dependency, npm install needs the network and raises one prompt. Record how many prompts appeared and why each one did.
Verification: watch whether it really ran pnpm test and whether the output carries the number of passing tests; if the tests went red, did it fix them itself or come back to ask you? This dimension shows the difference between a partner and a typist better than any other.
Cost: wall-clock time from start to report, plus the token usage it reports when the session ends. Afterwards run /review to have it review its own work, and record the number of review comments and how many you agreed with — that is the data the next section needs.
The same task through Claude Code: CLAUDE.md, Plan Mode, permission modes, end to end
Over to the Anthropic contractor. If you have not taken the Claude course, only a few confirmed features are used here, and they are enough to finish the comparison.
Briefing: Claude Code's project instruction file is CLAUDE.md in the repository root, corresponding exactly to AGENTS.md; copy the same content across (/init can generate a draft, but for comparability use the identical text today). The requirement text is unchanged, word for word.
Approval: Claude Code's permission model authorizes by tool type — reading files is allowed by default, while editing files and running commands ask each time by default, and /permissions can allowlist a class of command (pnpm test, say). It also has something with no direct counterpart in Codex: Plan Mode (toggled with Shift+Tab, or started with --permission-mode plan). In that mode it only reads, giving you a plan of how it intends to change things, and starts work only after you approve. For comparability today both sides use default permissions; but in the lab you can do an extra run with Plan Mode to see what the plan-first step does to the number of approvals and the amount of rework.
Verification: again, watch whether it runs the tests on its own initiative. How closely Claude Code follows a rule such as "always run the tests after a change" in CLAUDE.md, against how closely Codex follows the same rule in AGENTS.md, is something you can compare directly.
Cost: again, record wall-clock time and tokens. Claude Code has /context for current context usage, and a usage summary at the end of a session. Afterwards run /code-review to have it review its own work, recording the same data.
With both runs done you hold two run records. Fill them into the JSON template from the lab, and the comparison script generates the table for you.
How to read the comparison: most differences come from ways of working
With the table in hand, the most common misreading is "whoever wrote more tests is stronger." Slow down and read it in this order.
First, check comparability. Is the requirement text identical on both sides? Is the content of the project instruction file identical? Is the starting point the same commit? If any one of those differs, the source of every later difference becomes unexplainable.
Then look at the structural differences, which have nothing to do with model strength. A different number of approvals is mostly the two vendors' different default permission models: Codex draws the boundary with an operating-system sandbox and asks nothing inside it; Claude Code asks per tool type and lets you allowlist. That is not one being safer but two designs — one entrusting safety to runtime limits, the other to a human confirming each time. Different verification behavior mostly comes from where the "always run the tests" sentence sits in the instruction file and how explicitly it is written. For different costs, look first at how much of the token count is input — high input means it read more files, which may mean more caution, or may mean the instruction file never told it where to look.
Only last, look at capability differences. Given the same requirement, if one side's tests cover the edge case of a title longer than 200 characters and the other's do not, that is a capability-level difference — and it takes several runs to confirm, because a coding agent's output is inherently random and one run settles nothing.
The passage below is the core of the lab's comparison script: turning two records into one table. It calls no model, and both versions teach the same thing — normalize the data first, compare second.
interface RunRecord {
tool: 'codex' | 'claude-code'
promptChars: number
instructionsChars: number
approvals: { count: number; reasons: string[] }
verification: { ranTests: boolean; testsPassed: number; testsFailed: number }
cost: { minutes: number; inputTokens: number; outputTokens: number }
filesChanged: number
}
function row(label: string, pick: (r: RunRecord) => string | number, runs: RunRecord[]): string {
return `| ${label} | ${runs.map(pick).join(' | ')} |`
}
export function renderTable(runs: RunRecord[]): string {
const header = `| Dimension | ${runs.map((r) => r.tool).join(' | ')} |`
const sep = `| --- | ${runs.map(() => '---').join(' | ')} |`
return [
header,
sep,
row('Briefing: requirement + instruction file characters', (r) => r.promptChars + r.instructionsChars, runs),
row('Approval: interruptions', (r) => r.approvals.count, runs),
row('Verification: ran the tests itself', (r) => (r.verification.ranTests ? 'yes' : 'no'), runs),
row('Verification: passed / failed', (r) => `${r.verification.testsPassed} / ${r.verification.testsFailed}`, runs),
row('Cost: minutes', (r) => r.cost.minutes, runs),
row('Cost: tokens (input + output)', (r) => r.cost.inputTokens + r.cost.outputTokens, runs),
row('Files changed', (r) => r.filesChanged, runs),
].join('\n')
}from dataclasses import dataclass
from typing import Callable
@dataclass
class RunRecord:
tool: str
prompt_chars: int
instructions_chars: int
approvals: int
ran_tests: bool
tests_passed: int
tests_failed: int
minutes: float
input_tokens: int
output_tokens: int
files_changed: int
def row(label: str, pick: Callable[[RunRecord], object], runs: list[RunRecord]) -> str:
return f"| {label} | " + " | ".join(str(pick(r)) for r in runs) + " |"
def render_table(runs: list[RunRecord]) -> str:
header = "| Dimension | " + " | ".join(r.tool for r in runs) + " |"
sep = "| --- | " + " | ".join("---" for _ in runs) + " |"
return "\n".join(
[
header,
sep,
row(
"Briefing: requirement + instruction file characters",
lambda r: r.prompt_chars + r.instructions_chars,
runs,
),
row("Approval: interruptions", lambda r: r.approvals, runs),
row("Verification: ran the tests itself", lambda r: "yes" if r.ran_tests else "no", runs),
row("Verification: passed / failed", lambda r: f"{r.tests_passed} / {r.tests_failed}", runs),
row("Cost: minutes", lambda r: r.minutes, runs),
row("Cost: tokens (input + output)", lambda r: r.input_tokens + r.output_tokens, runs),
row("Files changed", lambda r: r.files_changed, runs),
]
)The table draws no conclusions; the conclusions are the few lines you write in the report template. One column of that template is labeled "does this difference come from the way of working or from capability," and every row of difference has to be filled in — a difference you cannot fill in is a place you do not yet understand.
Write one, review one: chaining the two tools into a daily workflow
D2 left a thread hanging when it covered code review: review and generation from the same vendor's model cannot catch a misunderstanding of the requirement, because both share the same understanding. The fix is to review with the other vendor. Both contractors are in the room today, so this is the moment to build that workflow.
The flow has three steps. Step one, A writes: complete the task with whichever you find handier (say Codex) and get the tests green. Step two, B reviews: hand the diff, the original requirement, and the acceptance criteria to the other one (Claude Code), asking it to find problems without changing code and to output structured review comments — file, line, problem, severity. Step three, a human decides: read the comments one by one and decide which go back to A for fixing and which get dismissed. You can run another review round after the fixes, but one is usually enough.
Both have an unattended mode, so this flow can be a script: codex exec for Codex, and claude -p with --output-format json for Claude Code (plus --allowedTools to hold the reviewer to read-only). What the reviewer receives matters greatly — always give it the original requirement, since with only the diff it degenerates into a linter; and always demand structured output, or you cannot automatically track which comments were accepted.
# Step one: A writes (Codex unattended mode)
codex exec "$(cat task.md). Run pnpm test afterwards and stop once green."
git diff > /tmp/change.diff
# Step two: B reviews (Claude Code unattended, read-only, structured output)
claude -p "The requirement is in task.md and the acceptance criteria in acceptance.md. Review only, change nothing, and output a JSON array of file, line, issue, severity." \
--allowedTools "Read,Grep,Glob" --output-format json < /tmp/change.diff > /tmp/review.json
# Step three: a human decides, and accepted comments go back to AWhen is this not worth doing? Three cases. First, when the task is small enough that reviewing costs more than the task — fixing a typo does not need two firms in session. Second, when the team only bought one vendor's allowance, since cross-vendor review means two bills and you have to weigh whether the extra problems found are worth the money. Third, when nobody reads the review comments — if the team habitually accepts everything in one click, the second vendor's opinion is just another layer of noise. All of this workflow's value comes from the human in step three, and with no human present the first two steps are waste.
Conversely, its highest-value cases are equally clear: the change affects several callers, the requirement itself is ambiguous, or this change is going to production. In those three, one independent opinion from a different model pays for itself the first time it catches a misreading.
Where to go next: from using tools to building them
Over five days you learned to get work done with the tools on the OpenAI side: having Codex change code locally and in the cloud, having it review code, writing your own small agents with the Responses API and the Agents SDK, and finally comparing and combining the two vendors' tools. This course is positioned at using them, and what it deliberately did not touch is building them.
Three directions, depending on your situation.
To get fluent with the other vendor too: take Mastering Claude, five days, structured day for day against this course and using the same TODO API task. Finish both and you hold a complete two-tool comparison.
To learn how Codex and the Agents SDK are built underneath: take From Frontend Engineer to Agent Engineer in 30 Days. It starts on day one with the LLM API and hand-builds the agent loop, the tool system, and multi-agent orchestration all the way to a production-grade gateway and worker pool. The run function, handoffs, and guardrails you used today all get implemented by hand there.
To go deep on one layer: how to write the MCP server you wired up on D2, and how to design the skills from D2 into reusable capabilities, are the subjects of the upcoming specialist courses mcp-7days and agent-skills-7days. Both start from the assumption that you can already use Codex or Claude Code, which places them right after today.
Finally, back to this course's analogy. The two contractors work differently, but the way you manage them is the same: write a clear onboarding handbook, draw clear permission boundaries, require them to run the verification before reporting, and have the other one review anything important. That method belongs to no vendor. It belongs to you.
Source Reading
Hands-On Lab
The code is in labs/codex-mastery/day-05-dual-tool-compare, with four exercise points cut out of starter/ and complete answers in solution/. The script calls no model at all, and MOCK=1 substitutes built-in sample records for your own two JSON files so you can see the shape of the table first.
- Prepare an identical starting point: commit the TODO API from D1, note the commit id, and
git worktree addtwo working copies, one per tool. - In the Codex copy, place AGENTS.md, run the task, run
/review, and fill outruns/codex.jsonper the fields ofruns/template.json. - In the Claude Code copy, place a CLAUDE.md with the same content, run the same requirement, run
/code-review, and fill outruns/claude-code.json. - Run
MOCK=1 pnpm startto see the sample table, thenpnpm start runs/codex.json runs/claude-code.jsonto generate your own. - Paste the table into
report-template.md, label every row as way of working or capability, and finish by writing your tooling conclusion and one mixed workflow.
Interview Questions
Today's 3 questions are in the question bank below, weighted toward the comparable dimensions for choosing a coding agent, the benefit and cost of a mixed workflow, and how to explain the trade-off to a team. Expand each one and read the analysis before the key points — practicing the derivation beats memorizing bullets.
Checklist and Tomorrow
- Run the same task on both Codex and Claude Code, and record comparable data across four dimensions
- Explain how the two coding agents differ in project context, approval model, and verification habits, and justify a choice to a team
- Set up a write-one-review-one mixed workflow, and know when it isn't worth it
- For any row of difference in the comparison, say whether it comes from the way of working or from capability
- All 4 acceptance criteria of the lab pass
- Answer at least 2 of the 3 interview questions without looking at the key points
This is the course's last day. Look back at yourself on D1: you were installing Codex then, and now you can put two vendors' tools in the same table and know where the differences come from. Next, go fill in the other side with Mastering Claude, or go build what you used today by hand in the 30-day course.
Interview questions
Your team must pick between two coding agents. How do you propose a comparison that teammates can both understand and verify?团队要在两家 coding agent 之间选一个,你怎么给出一套可以向团队解释、也能被验证的对比维度?
Common in ChinaCommon overseasIntermediate#coding-agent#evaluation#decision-makingHow to reason about it · think before answering
- This tests methodology, not a verdict; leading with 'I prefer X' signals weak engineering judgment. Show how you make the comparison reproducible.
- Give the dimensions: instruction effort (prompt and instruction-file size), approvals (how many interruptions and why), verification (does it run tests unprompted, what happens on red), cost (time, tokens, money). All are measurable in your own repo.
- State the preconditions for comparability: same starting commit, identical requirement text, identical instruction-file content, default permissions, and 'run tests before reporting' on both sides.
- Then the reading order: check comparability, then structural differences (permission model, placement and wording of rules), and only then capability differences, which need several runs and a median.
- For the team: label every differing row as 'workflow' or 'capability'; workflow gaps are closed by configuration, capability gaps drive the choice.
- Expect the follow-up: why not benchmarks? They score standard problems with one number, while teams change legacy repos and care about four dimensions.
分析过程 · 先想清楚再作答
- 这题考的是方法论而不是结论。上来就说「我觉得 X 好」会被判为没有工程判断;面试官想听的是你怎么让比较可复现。
- 先给维度:交代(写多少需求、准备多少说明文件)、审批(中断几次、为了什么)、验证(是否主动跑测试、红了怎么办)、成本(时间、token、钱)。这四项都能在自己的仓库里量出来。
- 再给可比性的前置条件:同一个起点 commit、同一段需求文字、说明文件同内容、默认权限、都要求跑完测试再汇报;有一项不同,差异就说不清来源。
- 然后是读数的顺序:先查可比性,再看结构性差异(权限模型、说明文件的位置与措辞导致的行为差别),最后才看能力差异,而且能力差异要多次运行取中位数。
- 落到团队沟通:报告里每一行差异都标「来自工作方式还是能力」,工作方式的差异靠配置弥补,能力差异才影响选型。
- 可预期的追问:榜单为什么不够?榜单测标准题,团队干的是有历史包袱的仓库里的改动,且榜单只给一个分数、不给四个维度。
Key points
- Four measurable dimensions: instruction effort, approvals, verification, cost, all measured in your own repo
- Comparability first: same commit, same prompt, same instruction file, default permissions, tests required
- Read in order: comparability, structural differences, then capability, with medians over several runs
- Label each gap as workflow or capability; only capability gaps should drive the decision
答题要点
- 四个可量维度:交代、审批、验证、成本,全部在自己仓库里测
- 可比性前置:同起点、同需求、同说明文件、默认权限、都要求跑测试
- 读数顺序:可比性、结构性差异、能力差异;能力差异要多次运行取中位数
- 每行差异标「工作方式还是能力」,前者靠配置弥补,后者才决定选型
Where does the 'one vendor writes, the other reviews' workflow pay off, and when is it not worth it?「一家写、另一家审」的混用工作流收益在哪?什么情况下不值得?
Common in ChinaCommon overseasIntermediate#code-review#workflow#coding-agentHow to reason about it · think before answering
- The crux is 'not worth it'; listing benefits without costs reads as never having sat in front of a budget.
- Source of value: when one model both writes and reviews, they share one reading of the requirement, so misreads slip through; a second vendor catches exactly those, plus complementary blind spots.
- How to make it pay: the reviewer needs the original requirement and acceptance criteria, not just the diff, or it degrades into lint; demand structured output so acceptance can be measured; a human makes the final call.
- Not worth it when the task is smaller than the review, when only one vendor's quota exists and the extra bill outweighs extra findings, or when nobody reads review comments carefully.
- Most worth it when a change touches many callers, the requirement is ambiguous, or the change ships to production; one caught misread pays for it.
- Expect the follow-up: can it be automated? Both vendors have headless modes so writing and reviewing can be scripted, but the human adjudication step cannot be removed.
分析过程 · 先想清楚再作答
- 题眼在「不值得」。只讲收益不讲代价,是没在预算表前坐过的人的答法。
- 先说收益的来源:同一家模型写与审共享同一份对需求的理解,需求理解偏差抓不出来;换一家审,最大的增量正是这类偏差,其次是不同模型的盲区互补。
- 再说怎么做才有收益:审查方必须拿到需求原文与验收标准而不只是 diff,否则退化成 lint;必须要求结构化输出,否则无法统计采纳率;最后一步必须由人裁决。
- 不值得的三种情况:任务小到审查成本高于任务本身;团队只有一家的额度,跨家意味着双份账单且多抓出的问题不值这笔钱;审查意见没人认真看,多一家只是多一层噪音。
- 最值的三种情况:改动影响多个调用方、需求本身有歧义、改动要上生产——抓出一个理解偏差就回本。
- 可预期的追问:能不能自动化?两家都有脱手模式,写与审都能脚本化,但「人裁决」这一步不能省,否则前两步就是浪费。
Key points
- Value comes from an independent reading of the requirement, catching misreads a same-vendor review misses
- The reviewer needs the requirement and acceptance criteria, must output structured findings, and a human adjudicates
- Not worth it for tiny tasks, single-vendor budgets, or teams that do not read reviews
- Most valuable for multi-caller changes, ambiguous requirements and production deploys
答题要点
- 收益来自独立的需求理解:换一家审能抓出同家审查抓不到的理解偏差
- 审查方要拿到需求原文与验收标准、输出结构化意见,最后由人裁决
- 不值得:任务太小、只有一家额度、没人认真看意见
- 最值:影响多个调用方、需求有歧义、要上生产
How do you judge the quality of a coding agent's output on a task, beyond whether it ran?怎么评价一个 coding agent 这次任务的输出质量,而不只是看它跑没跑通?
Common in ChinaCommon overseasDeep dive#coding-agent#evaluation#qualityHow to reason about it · think before answering
- This tests whether you treat green tests as the finish line; 'check the tests' is the pass mark, differentiation lies beyond it.
- Four layers: correctness (do the tests cover the requirement's edges such as overly long titles or a string for done), contract (does the error shape match the spec exactly or did it improvise), scope (did it touch forbidden files, add dependencies or change defaults silently), maintainability (constants extracted, tests isolated, naming consistent with the repo).
- How to measure: correctness by adding your own counterexamples beyond its tests; contract and scope by diffing against the requirement line by line; maintainability via a structured review by a second model or a person.
- Add variance: one run proves nothing; run the same requirement three times and treat high variance as a quality signal in itself.
- Expect the follow-up: can you trust its 'done, tests pass'? Only what you can reproduce; rerun tests and read the diff yourself, the agent's report is a lead, not evidence.
分析过程 · 先想清楚再作答
- 这题考的是你有没有把「测试绿了」当终点。答「看测试」是及格线,区分度在测试之外。
- 拆成四层:正确性(测试是否覆盖了需求里的边界,比如 title 超长、done 传字符串)、契约(错误响应形状是否与需求一字不差,还是它自作主张改了)、范围(有没有改不该改的文件、有没有偷偷加依赖或改默认值)、可维护性(校验规则是否抽成常量、测试是否隔离、命名是否与仓库一致)。
- 再说怎么量:正确性看它写的测试之外你再补的反例能不能过;契约与范围看 diff 与需求逐条对照;可维护性交给第二家模型或人做结构化审查。
- 补一条随机性:单次结果不能下结论,同一需求跑三次看方差,方差大本身就是一个质量信号。
- 可预期的追问:它自己说「已完成并通过测试」能信吗?只信你能复现的部分——在你的机器上重跑测试、看 diff,agent 的汇报是线索不是证据。
Key points
- Four layers: correctness, contract, scope, maintainability; green tests cover only part of correctness
- Verify correctness with your own counterexamples, contract and scope by diffing against the spec, maintainability via structured review
- Run the same requirement several times; high variance is itself a quality signal
- The agent's report is a lead, not evidence; trust only what you reproduce
答题要点
- 四层:正确性、契约、范围、可维护性,测试绿只是正确性的一部分
- 正确性用自己补的反例验证,契约与范围对照需求逐条看 diff,可维护性做结构化审查
- 同一需求跑多次看方差,方差大本身是质量信号
- agent 的汇报是线索不是证据,只信自己能复现的部分