Home › Compare

Claude Code vs Codex vs OpenCode, side by side

The same hook, MCP server and skill, set up on each agent, and what each one did. Every row comes from a tutorial that names its versions and the date it was run. No affiliate links.

The matrix

Run on 2026-09-25. Each heading links to the tutorial with the commands, versions and what we could not verify.

Hooks and plugins

Claude CodeCodexOpenCode
Registerhooks in settings.jsonhooks.json or [hooks]plugin file
Extra step before it runsaccept workspace trusttrust each hook with /hooksrestart
Block a tool calldeny or exit 2deny or exit 2 (no ask)throw
Add context for the modeladditionalContext, 10,000 charactersadditionalContext, about 2,500 tokens by defaultSDK session.prompt with noReply
Session record on diskJSON lines, one file per sessionJSON lines, one file per sessiona SQLite database

One MCP server

Claude CodeCodexOpenCode
Project file.mcp.json.codex/config.toml, trusted projects onlyopencode.json
Approval before useonce per project, except in -pnone in the home config; a project file needs a trusted projectnone
Does the list command connect?yes, once approvednoyes
A broken server in a real sessionexits 0 and the model answers; the only sign is a failed status in the stream-json start-up eventexits 0 and the model answers; two error lines on standard errorexits 0 and says nothing about the server

One skill

Claude CodeCodexOpenCode
Reads .claude/skills/yesnoyes
Reads .agents/skills/noyesyes
Reads .opencode/skills/nonoyes
A skill with no descriptionstill works by name, but was not chosen for a plain promptskipped, with a message on standard error onlyloads only when asked by name

What a Crossing Guard rule can do on each

Read from the framework source. The installers are here →

Claude CodeCodexOpenCodeCursor
Connectionhook entries in settings.jsonhook entries in hooks.jsonone plugin filehook entries in hooks.json
Deny a tool callyesyes, once you trust the hookon OpenCode 1.18.0; other versions only recordyes
Hold a call for a personyes, for up to 55 secondsyes, for up to 55 secondsno, the call is deniedno, the call is denied
Shared memory at session startyesyesnono

On every agent, a deny rule is evaluated inside the hook, so it still applies when the daemon is not running. When a held call gets no answer, it is denied. What happens when something fails →

The Cursor connection does not cover Cursor CLI, Tab or Cloud Agents.