A Claude Code harness that refuses to let a session end until the plan has survived a real, adversarial review by Codex CLI.
codex-gate wires a Stop hook and a skill together so that every implementation plan written in this project must be reviewed — and explicitly approved — by an independent model (OpenAI Codex via the codex CLI) before Claude Code is allowed to finish its turn.
No rubber stamps. No self-review. The gate only opens when a second model, in a persistent review session, says the plan has no remaining real issues.
Claude writes/edits a plan in plans/
│
▼
Claude tries to stop ──► Stop hook (review_gate.py)
│ │
│ marker found? ───┤
│ yes │ no
▼ ▼
session ends hook blocks with reason
"use the codex-review skill"
│
▼
codex-review skill kicks in:
1. send full plan to `codex exec`
2. fix real issues / push back on bad ones
3. resume the SAME codex session, re-check
4. loop until Codex explicitly signs off
│
▼
append <!-- CODEX-REVIEW-APPROVED --> to the plan
│
▼
next stop attempt passes
Key properties:
- Independent reviewer. The review is performed by an actual
codex execprocess, not by Claude judging its own work. - Single persistent session. Every follow-up round resumes the same Codex
thread_id, so the reviewer keeps full context on what was already raised and fixed. - Genuine consensus, not attrition. The skill's ground rules forbid writing the approval marker while knowingly leaving an issue unresolved, and equally forbid caving to out-of-scope or over-engineered objections without arguing back.
- No fixed round cap. The loop runs until Codex explicitly states there are no remaining real issues.
- Claude Code (hooks + skills support)
- Codex CLI ≥ 0.140.0, authenticated (
codex --versionto verify) - Python 3
codex-gate ships as a Claude Code plugin — this repo is both the plugin and its own marketplace. Inside Claude Code, run:
/plugin marketplace add barkaaa/codex-gate
/plugin install codex-gate@codex-gate
That's it. The Stop hook and the codex-review skill are registered automatically. Then create the plan directory in your project (or point CODEX_REVIEW_PLAN_DIR at an existing one):
mkdir -p plansManual installation (without the plugin system)
-
Copy the hook and the skill into your project's
.claude/directory:git clone https://github.com/barkaaa/codex-gate.git cd /path/to/your-project mkdir -p .claude/hooks .claude/skills cp ../codex-gate/hooks/review_gate.py .claude/hooks/ cp -r ../codex-gate/skills/codex-review .claude/skills/ -
Register the Stop hook in your project's
.claude/settings.json(merge into the existing file if you already have one):{ "hooks": { "Stop": [ { "hooks": [ { "type": "command", "command": "CODEX_REVIEW_PLAN_DIR=plans python3 \"$CLAUDE_PROJECT_DIR/.claude/hooks/review_gate.py\"" } ] } ] } } -
Restart Claude Code (or reopen the project) so the hook and skill are picked up.
Alternatively, just clone this repo and open it directly in Claude Code — the .claude/ directory is already fully wired up, so the repo doubles as a live demo.
-
Open this directory in Claude Code.
-
Ask Claude to write an implementation plan — it will land as a
*.mdfile inplans/. -
Let Claude finish. The Stop hook fires, finds no approval marker on the newest plan, and blocks the stop.
-
Claude invokes the
codex-reviewskill, runs the real review loop against Codex, updates the plan, and — only after explicit sign-off — appends:<!-- CODEX-REVIEW-APPROVED --> -
The next stop attempt passes and the session ends.
| Setting | Where | Default | Description |
|---|---|---|---|
CODEX_REVIEW_PLAN_DIR |
env var in the Stop hook command (.claude/settings.json) | plans |
Directory scanned for plan *.md files. The hook only gates the most recently modified plan. |
| Approval marker | review_gate.py | <!-- CODEX-REVIEW-APPROVED --> |
The exact line that must appear in the latest plan for the gate to open. |
The hook exits silently (allowing the stop) when: the plan directory is empty, the latest plan already carries the marker, or stop_hook_active is set (preventing infinite block loops).
codex-gate/
├── .claude-plugin/
│ ├── plugin.json # plugin manifest
│ └── marketplace.json # this repo doubles as its own marketplace
├── hooks/
│ ├── hooks.json # plugin Stop hook registration
│ └── review_gate.py # the gate: blocks stop until marker present
├── skills/
│ └── codex-review/
│ └── SKILL.md # the review loop protocol + Codex CLI playbook
├── .claude/ # self-hosted demo wiring (clone & open = live demo)
│ ├── settings.json
│ ├── hooks/review_gate.py
│ └── skills/codex-review/SKILL.md
├── plans/ # implementation plans under review (starts empty)
├── LICENSE
└── README.md
- The
codex-reviewskill embeds hard-won operational knowledge about scripting Codex CLI non-interactively (codex exec, stdin handling,--jsonthread IDs,resumequirks, sandbox network fallback timing). See SKILL.md for the full playbook. - In sandboxed environments, each Codex call can take 100–150+ seconds before producing output due to WebSocket→HTTPS fallback retries. Budget timeouts accordingly (the skill recommends ≥ 280 s).
- Real end-to-end runs have taken 2–3 review rounds for non-trivial plans; several rounds is normal, not a failure mode.
MIT