How the Codex Plugin Implements the Stop-Review-Gate Hook

The stop-review-gate hook is triggered automatically before every review session to query an LLM whether to abort the pipeline, implementing a safety gate that halts execution if the AI detects conditions that warrant stopping.

The openai/codex-plugin-cc repository provides a mechanism to halt review workflows before they consume LLM resources. This article explains how the stop-review-gate hook works by examining the runtime trigger sequence, the decision logic that queries the language model, and the specific source files that orchestrate this safety check.

Trigger Sequence: When the Stop-Review-Gate Hook Fires

The hook activates through a six-step pipeline managed by the plugin runtime. Each phase ensures the gate evaluates context before the LLM processes a full review.

  1. Review command execution – When a user runs codex review or any workflow triggering the review step, the runtime prepares a review job.
  2. Hook registration – During pipeline initialization, the runtime scans plugins/codex/hooks/hooks.json and registers all hooks marked with the "review-gate" purpose, including stop-review-gate-hook.mjs.
  3. Pre-review phase – Immediately before building the review prompt, the runtime calls the main() function inside stop-review-gate-hook.mjs.
  4. Decision logic – The runStopReview() function loads the prompt template from plugins/codex/prompts/stop-review-gate.md, collects contextual data (current working directory, job list, existing notes via plugins/codex/scripts/lib/state.mjs), and sends the assembled request to the LLM via the internal codex client in plugins/codex/scripts/lib/codex.mjs.
  5. Parse and evaluate – The hook uses parseStopReviewOutput() to parse the LLM's JSON response. If the object contains { "stop": true, "reason": "..." }, the helper emitDecision() writes a decision payload to the job’s control channel.
  6. Pipeline halt or continuation – The runtime consumes the payload. A true stop value aborts the review pipeline and logs the reason as a note; a false value allows normal review processing to proceed.

Hook Registration and Manifest Configuration

The runtime discovers the gate through a declarative manifest. In plugins/codex/hooks/hooks.json, the script is registered with the "review-gate" purpose, ensuring the plugin calls it automatically during the pre-review phase.

This registration decouples the trigger mechanism from the business logic, allowing the runtime to orchestrate hook execution without hardcoding specific gate checks into the review command itself.

The Decision Logic: From Prompt to Abort

The core implementation in plugins/codex/scripts/stop-review-gate-hook.mjs orchestrates the LLM query and response handling. The runStopReview() function performs three critical operations:

  • Context assembly – Gathers state data including the current working directory, pending jobs, and existing review notes from plugins/codex/scripts/lib/state.mjs.
  • LLM querying – Sends the assembled context plus the stop-review-gate prompt template to the LLM using the codex client exported from plugins/codex/scripts/lib/codex.mjs.
  • Response handling – Passes the raw LLM output to parseStopReviewOutput(), which validates the JSON structure and extracts the boolean stop field and optional reason string.

When stop evaluates to true, emitDecision() serializes the decision and writes it to the job’s control channel, signaling the runtime to terminate the pipeline before the review phase begins.

Prompt Template Structure

The hook relies on a markdown prompt template located at plugins/codex/prompts/stop-review-gate.md. This template instructs the LLM to act as a safety-oriented assistant and mandates a strict JSON output format:

You are a safety‑oriented assistant.  
Given the list of pending jobs and the current repository state, decide
whether the review should be stopped. Respond with JSON:

{
  "stop": <true|false>,
  "reason": "<optional short explanation>"
}

The runStopReview() function injects contextual data into this template before transmission, ensuring the LLM has sufficient information to make an informed gate decision.

Runtime Integration Example

The following example demonstrates how the plugin runtime invokes the gate during review preparation:

import { runStopReview } from "./stop-review-gate-hook.mjs";

async function prepareReview(session) {
  // Set up job list, load state, etc.
  await runStopReview(process.cwd(), { session });
  // If the hook emitted a “stop” decision, the runtime will throw
  // and the following review steps will be skipped.
}

If runStopReview() triggers an abort decision, the runtime intercepts the control payload and halts execution, preventing subsequent review logic from executing.

Summary

  • The stop-review-gate hook triggers automatically before every review via the "review-gate" purpose declared in plugins/codex/hooks/hooks.json.
  • The runStopReview() function in plugins/codex/scripts/stop-review-gate-hook.mjs orchestrates the LLM query using the prompt template at plugins/codex/prompts/stop-review-gate.md.
  • If the LLM returns { "stop": true, "reason": "..." }, emitDecision() writes a payload to the control channel that halts the pipeline and logs the explanation.
  • Contextual data is supplied by plugins/codex/scripts/lib/state.mjs and LLM communication uses the client in plugins/codex/scripts/lib/codex.mjs.

Frequently Asked Questions

What is the purpose of the stop-review-gate hook in the Codex plugin?

The hook serves as an automated safety mechanism that evaluates whether a review session should proceed. By querying the LLM with contextual data about the job state and repository conditions, it can abort reviews that meet specific cancellation criteria before consuming additional compute resources.

Which files are responsible for the stop-review-gate functionality?

The implementation spans four key files: plugins/codex/scripts/stop-review-gate-hook.mjs contains the orchestration logic; plugins/codex/prompts/stop-review-gate.md defines the LLM instructions; plugins/codex/hooks/hooks.json registers the hook with the runtime; and plugins/codex/scripts/lib/state.mjs and plugins/codex/scripts/lib/codex.mjs provide state management and LLM communication utilities.

How does the hook communicate its decision to abort a review?

Inside stop-review-gate-hook.mjs, the emitDecision() function writes a JSON payload containing { "stop": true, "reason": "..." } to the job’s control channel when parseStopReviewOutput() detects a stop signal in the LLM response. The runtime monitors this channel and terminates the review pipeline upon receiving a stop decision.

Can the stop-review-gate logic be customized?

Yes, administrators can modify the decision criteria by editing the plugins/codex/prompts/stop-review-gate.md template to change the instructions given to the LLM. However, the JSON response format expected by parseStopReviewOutput() must remain compatible to ensure the runtime correctly interprets the stop signal.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →