Codex vs Claude Code: an honest comparison from someone shipping into both

They have converged. Same shape, same concepts, mostly the same words. What is left is a short list of real differences, and almost all of them live in the extension layer nobody demos.

The kitstarter robot beside a balance scale holding one identical block on each pan, the beam perfectly level

Codex and Claude Code are both terminal coding agents. Both read a project instruction file, both run tool calls with an approval step, both support hooks, skills, MCP servers and subagents. If you are hoping this page ends with one of them being twice as good, it does not, and anyone telling you otherwise is selling something. The useful comparison is narrower and more practical: where do they actually behave differently, and which of those differences will you feel? We maintain the same behavior kit for both, which means we have had to implement every one of these differences rather than describe it. That is the only credential this page has, and it is the reason it can be specific.

The short answer

For day-to-day coding, the gap is smaller than the internet suggests, and it moves every few weeks. Both write good code. Both are fast. Both will happily build the wrong thing if you ask vaguely. The thing you will actually feel is the approval model, and there the two have made genuinely different bets.

Codex bets on configured trust: hooks have to be reviewed and trusted before they run, projects have to be trusted before their config loads, and each MCP server can be given its own approval mode, down to individual tools. Claude Code bets on programmatic control: its hooks can return a decision that denies a tool call outright, which Codex's cannot do today. Neither bet is obviously right. One is a better place to configure safety; the other is a better place to enforce it. Everything below is the detail behind that sentence.

Two stacks of blocks of identical height standing side by side, differing only in the single block on top
Same height, same shape. The whole comparison is the one block that differs.

The differences that are real

Only rows where the two genuinely differ. Anything the two do the same way (AGENTS.md, MCP over stdio and HTTP, subagents, plan-before-build, image input) is left out, because a comparison table padded with ties is how you make two similar things look different.

CapabilityCodexClaude Code
Hook config lives in.codex/hooks.json or an inline [hooks] table in config.toml, per project or in ~/.codex. All matching layers run; a higher layer does not replace a lower one.the hooks object in settings.json, per project or in ~/.claude.
Before a new hook runsyou review and trust it via /hooks. Trust is bound to the hook's hash, so an edited command needs re-trusting.nothing. A hook in settings.json runs.
Can a hook deny a tool call?not today. PreToolUse is warning-only.yes. PreToolUse returns permissionDecision: "deny" and the call does not happen.
The edit tool a matcher must nameapply_patch (plus Edit/Write). A matcher that only says Edit|Write silently never fires.Edit, Write, MultiEdit, NotebookEdit.
Hook timeout default600 seconds if you omit timeout. Set it.set per hook; the kit wires an explicit value either way.
Skills live in.agents/skills/<name>/SKILL.md, scanned from your working directory up to the repo root, plus ~/.agents/skills..claude/skills/<name>/SKILL.md, plus ~/.claude/skills.
Invoking a skill by name$name, or /skills to browse./name.
Skill list context budgetthe initial list is capped at 2% of the context window, or 8,000 characters when it is unknown. Past that, Codex shortens descriptions, then omits skills and warns.no published cap.
MCP approval granularityper server and per tool: default_tools_approval_mode of auto, prompt, writes or approve, overridable on a single tool.permission rules by tool pattern in settings.json.
MCP config lives in[mcp_servers.<name>] in config.toml, shared by the CLI, the IDE extension and the ChatGPT desktop app..mcp.json, or claude mcp add.
A session-end eventnone published. Turn-scope events end at Stop and SubagentStop.SessionEnd.
Status linenot a hook surface.the statusLine key in settings.json runs a command.
Codex rows verified against OpenAI's Codex documentation on 2026-07-16. Claude Code rows verified against the hook set kitstarter wires and runs in production. Both move fast; re-check anything you are about to depend on.

Hooks: same event names, one decisive difference

The lifecycle names have converged almost completely. SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, PreCompact, SubagentStart, Stop: both have them, and the config is close enough that porting a hook is a rename, not a rewrite. Codex additionally publishes PostCompact, SubagentStop, and a PermissionRequest event that fires around the approval itself. Claude Code publishes SessionEnd, which Codex does not.

That last one is not academic, and here is the receipt. We wire 12 handlers across 8 events on Claude Code, and 11 across 7 on Codex. The missing one is the session recap: it runs on SessionEnd, Codex has no equivalent event, so on Codex that feature does not exist. We did not find a clever workaround and we are not going to pretend a Stop hook is the same thing, because Stop fires at the end of every turn, not at the end of your session. When someone tells you their tool works identically across both agents, ask them which handler they dropped.

The difference that will actually change your design, though, is denial. A Claude Code PreToolUse hook can return a decision and stop an edit. A Codex PreToolUse hook can only speak. Our clarity engine is meant to lock file edits until the goal is confirmed, so on Codex it cannot: the adapter translates the deny into a plain warning, and the rule travels in the instruction injected at UserPromptSubmit instead. That works better than it sounds, because a good agent follows a clear instruction most of the time. But most of the time is not the same as never, and if your reason for wanting hooks is a hard gate, that is the whole ballgame. Watch PermissionRequest: it is the surface where this most plausibly closes.

Skills: same idea, different folder, one real constraint

A skill is a folder with a SKILL.md that carries a name and a description, in both tools. Both load the full instructions only when the skill is chosen, so the cost of having one installed is its description, not its body. The differences are the folder (.agents/skills versus .claude/skills), the sigil ($name versus /name), and one constraint Codex publishes and Claude Code does not.

Codex caps the initial skill list at 2% of the context window, or 8,000 characters when the window is unknown. Past that it shortens descriptions, then starts omitting skills. We ship 17 skills, whose names and descriptions total 5,683 characters, or 71% of that fallback budget before you have installed anything of your own. That is a real ceiling and we are closer to it than we would like. It is also the correct constraint to have: a description is a promise about when to trigger, and a budget is what stops a kit from installing forty of them. Claude Code publishes no such cap, which is more comfortable and less honest.

MCP: nearly identical, and Codex has the better knob

This is the closest race. The same servers work in both. The shape is the same: a command, args, and env for a local stdio server, or a URL for a streamable HTTP one. Codex keeps it in [mcp_servers.<name>] in config.toml and shares that config across the CLI, the IDE extension and the ChatGPT desktop app, which is genuinely nice: configure once, switch client, it is still there. Claude Code uses .mcp.json or claude mcp add.

Where Codex is straightforwardly ahead is approvals. default_tools_approval_mode takes auto, prompt, writes or approve, per server, overridable per tool. `writes` is the interesting one: it prompts for tools that are not marked read-only and waves through the ones that are. That is the ask-first principle expressed as one config key, applied to the exact surface where it matters most, since an MCP server is code you did not write handling data you did not vet. Almost nobody writing about Codex and MCP mentions it. If you take one thing from this page into your own config, take that key.

That one key is worth more than most of this table, so it gets its own page: our guide to Codex MCP covers it alongside the options whose defaults will surprise you, and the reason to treat everything a server returns as data rather than instructions.

What running the same kit in both actually taught us

Four things we would not have believed from the documentation, in the order they cost us time:

Trust is a hashCodex records hook trust against the hook's exact text. Our commands embed an absolute path to your Node binary, so upgrading Node re-queues every hook for review. Nothing is broken and nothing warns you in the way you expect. A tool that installs Codex hooks and never mentions /hooks will look broken on day one and mysterious on day ninety.
Two layers, two firesCodex runs all matching hooks from every config layer; a project layer does not override the user layer. Install the same kit globally and per project and every hook runs twice. Most config systems in a developer's life do the opposite, so this reads as a bug and is not one.
apply_patch or nothingCodex edits files with its own apply_patch tool. Port a Claude Code hook config across, keep its Edit|Write matcher, and your PreToolUse hook will never fire once. It will not error. It will just be quietly absent, which is the worst failure mode a safety check can have.
The response shapes differSame event names, different JSON coming back. SessionStart and SubagentStart want hookSpecificOutput.additionalContext; everything else wants a systemMessage. We ended up writing one adapter that translates at the boundary rather than forking every script, which is the single change that made supporting both tools sane.
The four differences that cost us real time. All four are invisible until you have shipped into both.

The larger lesson, and the reason this page exists: the two agents are converging on capability and diverging on posture. Codex wants you to declare what you trust, and then it will be permissive inside that boundary. Claude Code wants you to be able to write code that says no. If you only ever read feature lists, they look like the same product. They are not, and the difference shows up on the day something goes wrong rather than on the day you install.

So which one should you use?

The honest answer is that for most people, at most moments, it will not be the thing that decides whether the project ships. But the choice is not arbitrary either, so here is what we would actually tell a friend:

  1. Use Codex if you want safety configured rather than coded. The trust review on hooks, the trusted-project gate, and per-tool MCP approval modes are a coherent, thought-through model, and you get them by editing config rather than by writing scripts. Also pick it if you move between the CLI, an IDE and the ChatGPT desktop app, because MCP config follows you.
  2. Use Claude Code if you need a check that cannot be talked out of. A hook that returns a real deny is the only way to make a rule that survives an agent deciding it knows better. If you are enforcing something across a team, or the cost of one bad edit is high, that is worth more than any config elegance.
  3. Use both, honestly, if you already have both. They are not exclusive. AGENTS.md is read by both, so the rules that matter most travel for free, and the two do not fight over a repo. The tax is real but small: two config files and remembering which sigil summons a skill.
  4. Do not pick on benchmarks you read this month. Both ship headline features weekly, and every head-to-head is stale before it is indexed. We have our own benchmark harness and we are deliberately not quoting it here: it is a single-run internal result, and a comparison page is the last place an unearned number belongs.

And the thing that will improve your results more than either choice: the way you ask. Every failure mode we have measured, over-building, scope creep, confident wrong turns, starts with a request that was not specific enough to build from, and neither agent will fix that for you. Both will cheerfully build the wrong thing beautifully.

Which is the whole reason kitstarter exists, and it is a behavior kit rather than a Claude Code plugin: one install wires the ask-first rule, the hooks and the skills into both agents natively, with the honest caveat that on Codex the clarity lock instructs rather than blocks, because Codex will not let it block. The two spokes off this page go deeper: the Codex hooks guide covers the config shape and the trust gate, and the Codex skills guide covers the folder, the sigil, and that 8,000-character budget.

Common questions

Is Codex better than Claude Code? Not in general, and anyone answering that cleanly is guessing or selling. Both write good code, both are fast, and both ship features weekly. The clearest real difference is the approval model. Codex gates hooks behind a trust review and offers per-server and per-tool MCP approval modes, so safety is something you configure. Claude Code lets a PreToolUse hook return a decision that denies a tool call, so safety is something you can code. Pick on which of those you need.

What is the main difference between Codex and Claude Code? The extension layer. They agree on the big things: a project instruction file, tool calls with approval, hooks, skills, MCP and subagents. They differ in that Codex requires you to review and trust a hook before it runs, has no session-end event, and edits files with its own apply_patch tool, while Claude Code has a SessionEnd event, a status line surface, and a PreToolUse hook that can actually deny a call. Codex also publishes a cap on the skill list of 2% of the context window, or 8,000 characters when unknown.

Can I use Codex and Claude Code together on the same project? Yes, and it is common. They keep their config in different places, .codex and .claude, so they do not collide, and both read AGENTS.md, so your project rules only have to be written once. The practical cost is remembering that skills are $name in Codex and /name in Claude Code, and that a hook you write for one needs its matcher adjusted for the other, since Codex names its edit tool apply_patch.

Do Claude Code hooks work in Codex? Not as-is, but the port is small. The event names largely match, so the structure carries over, but three things must change: the matcher has to name apply_patch for edit events, the timeout is in seconds and defaults to 600, and the response JSON differs, since SessionStart and SubagentStart expect hookSpecificOutput.additionalContext while other events expect a systemMessage. The one thing that does not port at all is a deny: Codex's PreToolUse hook is warning-only today.

Does AGENTS.md work in both Codex and Claude Code? Yes. AGENTS.md is the piece of a setup that genuinely travels between agents, which is why kitstarter puts its ask-first rule there rather than in a tool-specific file. What does not travel is enforcement: hooks are configured per tool, and a rule that a hook enforces on Claude Code is only an instruction on Codex.

One kit, both agents, no cosplay

kitstarter installs natively into each: .codex/hooks.json and .agents/skills for Codex, settings.json and .claude/skills for Claude Code, and the ask-first rule in the AGENTS.md they both read. Where a tool cannot enforce something, we say so instead of shipping a placebo.

Get the kit · $20 $29Read the docs