# How the Stop-Review-Gate Functionality Works in openai/codex-plugin-cc: A Complete Technical Guide

> Understand the stop-review-gate in openai/codex-plugin-cc. This guide details how the automated safety layer reviews Claude turns, emitting ALLOW or BLOCK decisions to STDOUT.

- Repository: [OpenAI/codex-plugin-cc](https://github.com/openai/codex-plugin-cc)
- Tags: deep-dive
- Published: 2026-07-16

---

**The stop-review-gate functionality in openai/codex-plugin-cc is an automated safety layer that performs a Codex-driven review of the previous Claude turn before allowing a session to terminate, emitting either an "ALLOW" or "BLOCK" decision via JSON to STDOUT.**

The openai/codex-plugin-cc repository implements the stop-review-gate functionality as a final checkpoint to prevent problematic code changes from persisting when a Claude session ends. This gate intercepts stop commands, validates the recent work through a Codex companion process, and either permits the session to close or blocks it until issues are resolved.

## Entry Point and Hook Architecture

The stop-review-gate functionality begins execution at **`stop-review-gate-hook.mjs`** located in `plugins/codex/scripts/`. This Node.js module serves as the orchestration layer that coordinates the entire review process.

The hook receives its input via STDIN through the **`readHookInput`** function, which parses a JSON payload containing the current working directory, session ID, and the previous assistant message. After resolving the workspace root, the script loads the plugin configuration using **`getConfig`** and gathers metadata about any active Codex jobs by calling **`listJobs`** followed by **`filterJobsForCurrentSession`**.

## Configuration and State Management

Whether the gate executes depends on the **`stopReviewGate`** boolean flag stored in the state file at `plugins/codex/scripts/lib/state.mjs`. According to the source code, the default initialization sets `stopReviewGate: false` (lines 19‑25), meaning the gate remains inactive unless explicitly enabled.

When the flag is disabled, the hook immediately logs any running job notes and exits without performing a review. If enabled, the hook proceeds to **`buildSetupNote`** to verify that Codex is properly configured for the workspace. When setup is incomplete, the script logs a diagnostic message and aborts to prevent invalid review attempts.

## Review Prompt Construction

Once validated, the gate constructs the review prompt using the template file **[`stop-review-gate.md`](https://github.com/openai/codex-plugin-cc/blob/main/stop-review-gate.md)** in `plugins/codex/prompts/`. The **`interpolateTemplate`** function (from `lib/prompts.mjs`) injects the previous Claude response into the `CLAUDE_RESPONSE_BLOCK` placeholder within the template.

The resulting prompt instructs Codex to review only the work from the previous Claude turn and return a **compact** answer beginning with either `ALLOW:` or `BLOCK:`. This strict output format enables deterministic parsing of the review results.

## Executing the Review Task

The hook launches the actual review by spawning **`codex-companion.mjs`** (`plugins/codex/scripts/codex-companion.mjs`) as a synchronous child process using `spawnSync`. The task executes with a hard timeout of **15 minutes** defined by `STOP_REVIEW_TIMEOUT_MS`.

If the companion process times out, exits with an error code, or returns malformed JSON, the gate treats these conditions as failures and prepares a blocking decision. This ensures that infrastructure failures default to a safe state rather than allowing potentially flawed code to pass unchecked.

## Decision Parsing and Emission

After the companion task completes, the **`parseStopReviewOutput`** helper examines the first line of the output:

- **`ALLOW:`** → The gate passes and the session may terminate.
- **`BLOCK:`** → The gate fails and the session must remain active.
- **Any other output** → Treated as an unexpected answer, resulting in a block.

When blocking is required, the hook calls **`emitDecision`** to write a JSON object to STDOUT with the structure `{ decision: "block", reason: "..." }`. The surrounding Codex runtime consumes this payload and halts the stop operation, keeping the session alive. A note about any still-running jobs is appended to the reason for completeness.

Throughout execution, the hook writes diagnostic information to STDERR via **`logNote`**, ensuring users understand why a stop was blocked or why no review occurred.

## What Happens When the Gate Blocks a Stop

When the stop-review-gate functionality blocks a session termination, the user receives the blocking reason (for example, "Codex stop-time review found issues...") and the session remains open. The user must then either address the reported problems or bypass the gate using specific commands such as `/codex:review --wait` or `/codex:cancel <jobId>`.

This design enforces a final sanity check on the most recent code changes, ensuring that outstanding issues cannot be accidentally committed by closing the session.

## Code Examples

The following example demonstrates how the Codex runtime manually invokes the stop-review gate:

```javascript
import { spawnSync } from "node:child_process";
import path from "node:path";

const hookPath = path.resolve(
  __dirname,
  "plugins/codex/scripts/stop-review-gate-hook.mjs"
);
const input = {
  cwd: process.cwd(),
  last_assistant_message: "<Claude's previous turn output>",
  session_id: "session-123",
};

const result = spawnSync(
  process.execPath,
  [hookPath],
  {
    input: JSON.stringify(input),
    encoding: "utf8",
  }
);
console.log(result.stdout); // JSON decision: { "decision": "allow" } or { "decision": "block", "reason": "..." }

```

When using the interactive CLI, the gate triggers automatically:

```bash

# Pseudo-command that internally triggers the gate

/codex:stop

# Internal execution flow:

# 1️⃣ stop-review-gate-hook.mjs reads hook input via readHookInput

# 2️⃣ Builds prompt from stop-review-gate.md using interpolateTemplate

# 3️⃣ Runs codex-companion.mjs task with 15-minute timeout

# 4️⃣ Parses output with parseStopReviewOutput

# 5️⃣ Emits block decision if first line is "BLOCK:"

```

## Summary

- The entry point for the stop-review-gate functionality is **`stop-review-gate-hook.mjs`**, which orchestrates the review process.
- Execution is controlled by the **`stopReviewGate`** flag in `plugins/codex/scripts/lib/state.mjs`, defaulting to `false`.
- The review uses the **[`stop-review-gate.md`](https://github.com/openai/codex-plugin-cc/blob/main/stop-review-gate.md)** prompt template to instruct Codex to examine only the previous Claude turn.
- The companion script **`codex-companion.mjs`** executes the review synchronously with a **15-minute timeout** (`STOP_REVIEW_TIMEOUT_MS`).
- Valid outputs must begin with **`ALLOW:`** or **`BLOCK:`**; any other response triggers a block.
- The hook emits a JSON decision via **`emitDecision`** to STDOUT, which the runtime uses to either permit or halt session termination.

## Frequently Asked Questions

### How do I enable the stop-review-gate functionality?

You must set the **`stopReviewGate`** flag to `true` in the plugin state. By default, `plugins/codex/scripts/lib/state.mjs` initializes this value to `false` (lines 19‑25), so you need to explicitly toggle it to activate the safety check.

### Which file contains the review prompt template?

The prompt template resides at **[`plugins/codex/prompts/stop-review-gate.md`](https://github.com/openai/codex-plugin-cc/blob/main/plugins/codex/prompts/stop-review-gate.md)**. This Markdown file defines the instructions that Codex follows when reviewing the previous turn's changes, including the requirement to prefix responses with `ALLOW:` or `BLOCK:`.

### What happens if the review task times out or crashes?

If the **`codex-companion.mjs`** process exceeds the **15-minute timeout** (`STOP_REVIEW_TIMEOUT_MS`), exits with an error, or returns malformed JSON, the gate treats these as failures. The **`parseStopReviewOutput`** function will interpret these conditions as a blocking event, preventing the session from stopping until manually resolved.

### Can I bypass the gate if it incorrectly blocks my session?

Yes. When the gate blocks a stop, you can bypass it by using the **`/codex:review --wait`** command to wait for pending reviews to complete, or **`/codex:cancel <jobId>`** to cancel specific running jobs. The hook logs the specific blocking reason to STDERR via **`logNote`**, allowing you to diagnose whether to fix the reported issues or override the gate.