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 Code | Codex | OpenCode | |
|---|---|---|---|
| Register | hooks in settings.json | hooks.json or [hooks] | plugin file |
| Extra step before it runs | accept workspace trust | trust each hook with /hooks | restart |
| Block a tool call | deny or exit 2 | deny or exit 2 (no ask) | throw |
| Add context for the model | additionalContext, 10,000 characters | additionalContext, about 2,500 tokens by default | SDK session.prompt with noReply |
| Session record on disk | JSON lines, one file per session | JSON lines, one file per session | a SQLite database |
One MCP server
| Claude Code | Codex | OpenCode | |
|---|---|---|---|
| Project file | .mcp.json | .codex/config.toml, trusted projects only | opencode.json |
| Approval before use | once per project, except in -p | none in the home config; a project file needs a trusted project | none |
| Does the list command connect? | yes, once approved | no | yes |
| A broken server in a real session | exits 0 and the model answers; the only sign is a failed status in the stream-json start-up event | exits 0 and the model answers; two error lines on standard error | exits 0 and says nothing about the server |
One skill
| Claude Code | Codex | OpenCode | |
|---|---|---|---|
| Reads .claude/skills/ | yes | no | yes |
| Reads .agents/skills/ | no | yes | yes |
| Reads .opencode/skills/ | no | no | yes |
| A skill with no description | still works by name, but was not chosen for a plain prompt | skipped, with a message on standard error only | loads only when asked by name |
What a Crossing Guard rule can do on each
Read from the framework source. The installers are here →
| Claude Code | Codex | OpenCode | Cursor | |
|---|---|---|---|---|
| Connection | hook entries in settings.json | hook entries in hooks.json | one plugin file | hook entries in hooks.json |
| Deny a tool call | yes | yes, once you trust the hook | on OpenCode 1.18.0; other versions only record | yes |
| Hold a call for a person | yes, for up to 55 seconds | yes, for up to 55 seconds | no, the call is denied | no, the call is denied |
| Shared memory at session start | yes | yes | no | no |
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.