How dcg Detects and Handles Different AI Agents at Runtime: A Complete Technical Guide
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 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 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.
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_CODEfor Claude CodeAUGMENT_AGENTfor Augment CodeCODEX_CLIfor OpenAI CodexGEMINI_CLIfor Google GeminiCURSOR_AGENTfor Cursor IDE- And others including
AIDER,CONTINUE,COPILOT_CLI,HERMES_AGENT,GROK,ANTIGRAVITY, andPI
The function detect_from_environment() in 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 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:
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:
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.
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. The configuration system supports granular overrides per tool.
AgentProfile Structure
The AgentProfile struct defines per-agent security parameters:
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, 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:
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:
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:
dcgchecks CLI flags first, then environment variables, then parent process names to identify the invoking AI agent. - Type-safe representation: The
Agentenum andDetectionResultstruct insrc/agent.rsprovide exhaustive matching and caching for five minutes. - Per-agent policies:
AgentProfileconfigurations insrc/config.rsenable trust levels, pattern packs, and allow-list overrides specific to each tool. - Runtime integration:
src/main.rsmaps detected agents toHookProtocolvariants andAllowlistLayer::Agentfor 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, 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.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →