# How to Integrate DCG with Codex CLI Using the Hook Protocol

> Integrate DCG with Codex CLI using the hook protocol to block destructive Bash commands. Learn how to register DCG as a PreToolUse hook and secure your workflow.

- Repository: [Jeff Emanuel/destructive_command_guard](https://github.com/Dicklesworthstone/destructive_command_guard)
- Tags: how-to-guide
- Published: 2026-07-16

---

**You integrate DCG with Codex CLI by registering it as a `PreToolUse` hook in `~/.codex/hooks.json`; DCG then reads JSON from stdin, detects the Codex protocol via the `turn_id` field in [`src/hook.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/hook.rs), and returns a minimal `permissionDecision: "deny"` payload to block destructive Bash commands while silently exiting on safe commands.**

Destructive Command Guard (DCG) from the `Dicklesworthstone/destructive_command_guard` repository adds a safety layer to AI-driven terminal workflows by intercepting shell commands before execution. When you integrate DCG with Codex CLI using the hook protocol, it evaluates every Bash tool invocation in real time without requiring changes to existing Codex commands.

## Integrating DCG with Codex CLI via the PreToolUse Hook Protocol

The Codex CLI exposes a hook system that runs external binaries before tool execution. DCG implements the `PreToolUse` event handler, which receives a JSON document on stdin describing the pending command. This allows DCG to inspect and either block or allow the command before it reaches the shell.

### Hook Detection and Protocol Selection in [`src/hook.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/hook.rs)

In [`src/hook.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/hook.rs), the `detect_protocol` function inspects the incoming JSON to determine whether the caller is Codex or Claude. According to the DCG source code, Codex payloads contain a non-empty `turn_id` field. When this field is present, DCG selects `HookProtocol::Codex` and branches to Codex-specific formatting logic around line 1200.

```rust
// Protocol selection in src/hook.rs
match detect_protocol(&input) {
    HookProtocol::Codex => HookProtocol::Codex,
    _ => HookProtocol::Claude,
}

```

### Minimal Denial Payload Requirements for Codex

Codex is strict about extra fields in hook responses. As implemented in [`src/hook.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/hook.rs) around line 1500, DCG strips all DCG-only metadata from the denial output and emits only the fields the Codex parser expects. Any unexpected keys cause Codex to fail open with a parsing error.

```rust
// Denial payload for Codex (src/hook.rs, around line 1500)
if matches_destructive {
    eprintln!("⚠️  {rule_id}: {reason}");
    // Minimal JSON required by Codex
    println!(r#"{{"hookSpecificOutput":{{"hookEventName":"PreToolUse","permissionDecision":"deny","ruleId":"{rule_id}"}}}}"#);
    std::process::exit(0);
}

```

## Installing the DCG Hook for Codex CLI

You do not need to rebuild Codex or modify its source to add DCG. The project provides an installation script that registers the DCG binary as a hook in the Codex configuration directory.

### Automated Setup with [`install.sh`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/install.sh)

Run the following command to download and execute the installer:

```bash
curl -sSfL https://raw.githubusercontent.com/Dicklesworthstone/destructive_command_guard/main/install.sh | bash

```

The [`install.sh`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/install.sh) script creates a `PreToolUse` entry inside `~/.codex/hooks.json` that points to the DCG binary. The [`src/agent.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/agent.rs) file defines the `Agent::CodexCli` variant, which DCG activates when the `CODEX_CLI=1` environment variable is present or when the Codex protocol is detected.

### Manual Hook Configuration Structure

If you prefer to edit the file yourself, add an entry with the `event` set to `PreToolUse` and the `tool` filtered to `Bash`:

```json
{
  "command": "dcg",
  "args": [],
  "event": "PreToolUse",
  "tool": "Bash"
}

```

## Runtime Behavior: Deny vs. Allow

Once installed, DCG evaluates every Bash command that Codex attempts to run. The outcome depends on whether the command matches a destructive pattern in [`src/evaluator.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/evaluator.rs).

### Blocking Destructive Commands

When [`src/evaluator.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/evaluator.rs) flags a command as dangerous, DCG writes a human-readable warning to stderr and prints the minimal JSON denial object to stdout. Codex receives the `permissionDecision: "deny"` value and halts the tool call. The following command demonstrates a blocked invocation:

```bash
codex run -- bash -c "git reset --hard HEAD~3"

```

If the command is blocked, Codex receives the minimal JSON denial and prints the warning generated by DCG.

### Allowing Safe Commands Silently

If the command passes all safety checks, DCG produces no stdout output and exits with status code 0. This silent success path is essential because any unexpected stdout from the hook interferes with Codex's internal parsing. The [`src/config.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/config.rs) module loads per-agent profiles to ensure Codex-specific handling stays lightweight.

## Core Source Files Powering the Integration

Understanding the architecture helps when debugging or extending the integration.

- **[`src/main.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/main.rs)** — The CLI entry point that dispatches to the correct agent protocol based on the environment and active agent.
- **[`src/hook.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/hook.rs)** — Implements the `PreToolUse` hook, hosts `detect_protocol`, and formats the Codex-specific denial payload.
- **[`src/agent.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/agent.rs)** — Defines `Agent::CodexCli` and the detection logic tied to `CODEX_CLI=1`.
- **[`src/evaluator.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/evaluator.rs)** — The core pattern-matching engine that decides which commands are destructive.
- **[`src/config.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/config.rs)** — Loads per-agent profiles, including Codex-specific settings.
- **[`install.sh`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/install.sh)** and **[`uninstall.sh`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/uninstall.sh)** — Manage the `~/.codex/hooks.json` registration automatically.

## Summary

- Register DCG as a `PreToolUse` hook in `~/.codex/hooks.json` to integrate it with Codex CLI.
- The `detect_protocol` function in [`src/hook.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/hook.rs) identifies Codex by the presence of a `turn_id` field in the stdin JSON.
- Blocked commands return a minimal JSON payload containing `permissionDecision: "deny"` and no extra metadata.
- Safe commands exit silently with code 0, allowing Codex to proceed without modification.
- Run [`install.sh`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/install.sh) to automate hook registration, or manually edit `~/.codex/hooks.json` to point to the `dcg` binary.

## Frequently Asked Questions

### What happens if the DCG denial payload contains extra fields?

Codex treats extra fields in the hook response as a parsing error and fails open, which means the command might run unsafely. DCG avoids this by emitting only the required `hookEventName`, `permissionDecision`, and `ruleId` fields when handling `HookProtocol::Codex` in [`src/hook.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/hook.rs).

### How does DCG know it is running inside a Codex CLI session?

DCG detects the active agent through two mechanisms. First, it checks the `CODEX_CLI=1` environment variable defined in [`src/agent.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/agent.rs). Second, [`src/hook.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/hook.rs) inspects the incoming JSON for the `turn_id` field, which is unique to Codex payloads and triggers the `HookProtocol::Codex` branch.

### Can I use DCG with other agents besides Codex?

Yes. The `detect_protocol` function in [`src/hook.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/hook.rs) defaults to `HookProtocol::Claude` when the Codex `turn_id` field is absent. The [`src/main.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/main.rs) dispatcher supports multiple agent variants, so the same binary protects Claude and other AI CLI tools.

### Where does DCG output the warning when it blocks a command?

DCG writes the human-readable warning to stderr via `eprintln!`, while the structured JSON denial is written to stdout. This separation ensures Codex receives valid JSON on stdout without mixing in display text. The user sees the explanatory rule identifier and reason directly in the terminal.