# How dcg Detects and Handles Different AI Agents at Runtime: A Complete Technical Guide

> Learn how dcg detects and handles AI agents at runtime using CLI flags, environment variables, and parent process inspection for tailored policy restrictions. Technical guide.

- Repository: [Jeff Emanuel/destructive_command_guard](https://github.com/Dicklesworthstone/destructive_command_guard)
- Tags: deep-dive
- Published: 2026-07-14

---

**The `dcg` (Destructive Command Guard) crate identifies the invoking AI agent through a three-tier detection cascade—CLI flags, environment variables, and parent process inspection—then applies agent-specific security profiles to enforce tailored policy restrictions.**

The `dcg` binary in the [Dicklesworthstone/destructive_command_guard](https://github.com/Dicklesworthstone/destructive_command_guard) repository acts as a security intermediary for AI coding agents. Understanding how dcg detects and handles different AI agents at runtime is crucial for configuring per-tool permission boundaries and preventing destructive operations. The detection logic lives primarily in [`src/agent.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/agent.rs) and caches results for five minutes to avoid redundant system calls.

## The Three-Tier Detection Strategy

`dcg` employs a deterministic priority order when determining which AI agent invoked the command. Each tier serves as a fallback for the previous, ensuring robust identification across different execution environments.

### Explicit CLI Flag Override

The highest priority detection method checks for the `--agent=<name>` or `--agent <name>` argument supplied directly on the command line. This explicit flag immediately short-circuits the detection flow and forces `dcg` to treat the session as the specified agent regardless of environment variables or parent processes.

```bash
dcg --agent=codex-cli rm -rf /important/data

```

When present, this flag causes `detect_agent_with_details()` to return a `DetectionResult` with `method: DetectionMethod::Explicit` before any other checks execute.

### Environment Variable Signatures

If no CLI flag is present, `dcg` inspects environment variables for agent-specific signatures. Each supported AI coding agent sets a unique environment variable that acts as a fingerprint:

- `CLAUDE_CODE` for Claude Code
- `AUGMENT_AGENT` for Augment Code
- `CODEX_CLI` for OpenAI Codex
- `GEMINI_CLI` for Google Gemini
- `CURSOR_AGENT` for Cursor IDE
- And others including `AIDER`, `CONTINUE`, `COPILOT_CLI`, `HERMES_AGENT`, `GROK`, `ANTIGRAVITY`, and `PI`

The function `detect_from_environment()` in [`src/agent.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/agent.rs) iterates through these known variables, returning the first match with `method: DetectionMethod::Environment`.

### Parent Process Inspection

As a final fallback, `dcg` inspects the parent process name and arguments to identify known agent executables. On Linux, this reads `/proc/<pid>/comm`; on macOS and Windows, it executes `ps` or PowerShell commands respectively.

The system normalizes the executable basename and matches it against a lookup table mapping process names to `Agent` variants (e.g., `codex` → `CodexCli`, `gemini` → `GeminiCli`, `hermes-agent` → `Hermes`). This tier returns `method: DetectionMethod::Process` when successful.

## Core Detection Data Structures

The type system in [`src/agent.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/agent.rs) encodes the detection results through two primary structures that enable type-safe agent handling throughout the codebase.

### The Agent Enum

The `Agent` enum enumerates all built-in agents plus escape hatches for unknown or custom tools:

```rust
pub enum Agent {
    ClaudeCode,
    AugmentCode,
    Aider,
    Continue,
    CodexCli,
    GeminiCli,
    CopilotCli,
    CursorIde,
    Hermes,
    Grok,
    Antigravity,
    Pi,
    Custom(String),
    Unknown,
}

```

Variants like `Custom(String)` allow users to define arbitrary agent names in configuration, while `Unknown` serves as the default when no detection method succeeds.

### DetectionResult and Caching

The `DetectionResult` struct bundles the detection metadata:

```rust
pub struct DetectionResult {
    pub agent: Agent,
    pub method: DetectionMethod,
    pub matched_value: Option<String>,
}

```

The `DetectionMethod` enum distinguishes between `Explicit`, `Environment`, `Process`, and `None`. Detection results are cached for five minutes (`CACHE_TTL`) via internal memoization to prevent repeated parent process traversals during the same session.

## Detection Flow Implementation

The entry point `detect_agent()` provides a simple interface, while `detect_agent_with_details()` exposes the full detection metadata for logging and debugging purposes.

```rust
pub fn detect_agent() -> Agent {
    detect_agent_with_details().agent
}

pub fn detect_agent_with_details() -> DetectionResult {
    // 1️⃣ CLI flag
    if let Some(agent_name) = explicit_agent_from_args(std::env::args()) {
        return from_explicit(&agent_name);
    }

    // 2️⃣ Environment variables
    if let Some(result) = detect_from_environment() {
        return result;
    }

    // 3️⃣ Parent-process fallback
    if let Some(result) = detect_from_parent_process() {
        return result;
    }

    DetectionResult::unknown()
}

```

This implementation ensures that explicit user configuration always overrides implicit environment detection, preventing accidental misidentification when running `dcg` manually or in CI pipelines.

## Agent-Specific Configuration and Profiles

Once identification completes, `dcg` loads agent-specific security policies defined in [`src/config.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/config.rs). The configuration system supports granular overrides per tool.

### AgentProfile Structure

The `AgentProfile` struct defines per-agent security parameters:

```rust
pub struct AgentProfile {
    pub trust_level: TrustLevel,
    pub enabled_packs: Vec<String>,
    pub additional_allowlist: Vec<String>,
    // Additional policy overrides...
}

pub struct AgentsConfig {
    pub default: AgentProfile,
    pub profiles: HashMap<String, AgentProfile>,
}

```

The `Config::profile_for_agent(&agent)` method retrieves the appropriate profile, enabling scenarios where Claude Code might receive `TrustLevel::High` while an unknown agent defaults to `TrustLevel::Restricted`.

### Allow-List Layering

`dcg` implements a layered allow-list system where `AllowlistLayer::Agent` represents the first layer. This architecture enables per-agent command whitelisting—for example, allowing `cursor` specific IDE commands while blocking them for `codex-cli`.

## Runtime Policy Enforcement

The detected agent influences behavior beyond configuration files into the actual hook protocol and evaluation pipeline.

### Hook Protocol Selection

In [`src/main.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/main.rs), the detected agent maps to a specific `HookProtocol` variant. For instance, `Agent::CodexCli` triggers `HookProtocol::Codex`, which formats output and expects input according to the Codex CLI specification. This ensures compatibility with each agent's expected JSON schema or streaming format.

### Practical Integration Example

To inspect the active profile for the current agent:

```rust
use destructive_command_guard::agent::detect_agent;
use destructive_command_guard::config::Config;

fn show_profile(cfg: &Config) {
    let agent = detect_agent();
    let profile = cfg.profile_for_agent(&agent);
    println!("Agent {} uses trust level {}", agent, profile.trust_level);
}

```

To force a specific agent profile regardless of environment:

```rust
use destructive_command_guard::agent::{detect_agent_with_details, Agent};

fn main() {
    // Simulate --agent=codex-cli
    std::env::set_var("DCG_AGENT_OVERRIDE", "codex-cli");
    
    let details = detect_agent_with_details();
    assert_eq!(details.agent, Agent::CodexCli);
    assert_eq!(details.method, DetectionMethod::Explicit);
}

```

## Summary

- **Three-tier detection**: `dcg` checks CLI flags first, then environment variables, then parent process names to identify the invoking AI agent.
- **Type-safe representation**: The `Agent` enum and `DetectionResult` struct in [`src/agent.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/agent.rs) provide exhaustive matching and caching for five minutes.
- **Per-agent policies**: `AgentProfile` configurations in [`src/config.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/config.rs) enable trust levels, pattern packs, and allow-list overrides specific to each tool.
- **Runtime integration**: [`src/main.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/main.rs) maps detected agents to `HookProtocol` variants and `AllowlistLayer::Agent` for protocol-specific output formatting.

## Frequently Asked Questions

### How does dcg handle unknown or custom AI agents?

When detection fails to match any known signature, `dcg` returns `Agent::Unknown` and applies the default security profile. For custom tools, users can specify `Agent::Custom("my-agent")` via the `--agent` CLI flag or define named profiles in the configuration file, enabling bespoke policy enforcement without code changes.

### Can I override the detected agent for testing purposes?

Yes. Supplying `--agent=<name>` on the command line forces `dcg` to use that specific agent profile regardless of environment variables or parent processes. This explicit override returns `DetectionMethod::Explicit` and bypasses both environment and process inspection tiers entirely.

### What environment variables does dcg check for Claude Code detection?

`dcg` looks for the `CLAUDE_CODE` environment variable to identify Claude Code sessions. This variable is checked in `detect_from_environment()` within [`src/agent.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/agent.rs), and if present, immediately returns `Agent::ClaudeCode` with `DetectionMethod::Environment`.

### How does parent process detection work on different operating systems?

On Linux, `dcg` reads `/proc/<pid>/comm` to obtain the parent process name. On macOS and Windows, it executes platform-specific commands (`ps` or PowerShell) to query the process list. The detected executable basename is normalized and matched against a hardcoded table mapping process names to `Agent` variants, providing a robust fallback when environment variables are unset.