Skip to content

Instantly share code, notes, and snippets.

@nazt
Created January 18, 2026 09:08
Show Gist options
  • Select an option

  • Save nazt/3168a892d54e50612d3232ec523b68dc to your computer and use it in GitHub Desktop.

Select an option

Save nazt/3168a892d54e50612d3232ec523b68dc to your computer and use it in GitHub Desktop.
destructive_command_guard - AI Agent Safety Hook for Claude Code

destructive_command_guard

AI Agent Safety Hook - blocks dangerous commands before execution

Repo: https://github.com/Dicklesworthstone/destructive_command_guard Learned: 2026-01-18 16:01


Summary

Destructive Command Guard (dcg) is a high-performance safety hook that intercepts and blocks dangerous commands before AI coding agents can execute them. Born from real pain: AI agents like Claude Code, Gemini CLI, and Aider occasionally run catastrophic commands like git reset --hard, rm -rf ./src, or DROP TABLE users—destroying hours of uncommitted work in seconds.

Key Insight: Three-tier pipeline with SIMD-accelerated quick-reject means 95%+ of commands pass through in <10μs. Only commands containing dangerous keywords proceed to expensive regex matching.


Quick Reference

Item Value
Install curl -fsSL "https://raw.githubusercontent.com/.../install.sh" | bash -s -- --easy-mode
Entry point src/main.rs (CLI), src/hook.rs (Claude Code integration)
Key files evaluator.rs, context.rs, heredoc.rs, packs/
Language Rust
Supports Claude Code, Gemini CLI, Aider, any MCP-compatible agent

What It Does

The tool acts as a pre-execution firewall. When an AI agent attempts to run a shell command, dcg inspects it in sub-millisecond time, determines if it matches any destructive patterns, and either allows it silently or blocks it with a clear explanation and safer alternatives.

It supports 49+ modular security packs covering:

  • Databases: PostgreSQL, MySQL, MongoDB, Redis
  • Cloud: AWS, GCP, Azure
  • Containers: Docker, Kubernetes, Helm
  • CI/CD: GitHub Actions, GitLab CI, Jenkins
  • Core: git, rm, system commands

Also scans heredocs and inline scripts (e.g., python -c "os.remove(...)") using AST-based analysis.


How It Works

Three-tier pipeline optimized for speed:

Command → Tier 1: Quick Reject (<10μs) → Tier 2: Context Classification → Tier 3: Full Regex
              ↓ no keywords                     ↓ data only                    ↓ safe pattern
            ALLOW                              ALLOW                          ALLOW
  1. Quick Reject: SIMD-accelerated keyword matching. No keywords = pass through
  2. Context Classification: Mark spans as Executed, Data, InlineCode, HeredocBody
  3. Full Pattern Matching: Only on executable spans, against safe/destructive patterns

Fail-open philosophy: If analysis times out or fails to parse, command is allowed rather than blocking workflow.


Architecture

Component Purpose
hook.rs Claude Code/Gemini CLI hook protocol handler
evaluator.rs Core decision engine—normalizes, matches, verdicts
heredoc.rs Three-tier heredoc/inline-script detection
ast_matcher.rs Tree-sitter AST matching for embedded code
context.rs Span classification (Executed vs Data)
packs/ 49+ modular security packs
scan.rs Repository scanning for CI/pre-commit
config.rs Layered config (env > project > user > defaults)
pending_exceptions.rs Allow-once system with short codes
allowlist.rs Permanent exception management

Key Patterns

1. Three-Tier Filtering

// Tier 1: Quick reject via keyword presence (<10μs)
pack_aware_quick_reject(command, &enabled_keywords)

// Tier 2: Context classification
let spans = classify_command(command);  // Marks quoted strings as Data

// Tier 3: Full regex matching only on executable spans

Why clever: 95%+ of commands exit at tier 1 without memory allocation.

2. Context-Aware Span Classification

pub enum SpanKind {
    Executed,      // Must check patterns
    Data,          // Skip (quoted strings)
    InlineCode,    // bash -c "..." content - MUST check
    HeredocBody,   // Escalate to AST analysis
}

Why clever: Eliminates false positives like git commit -m "Fix rm -rf detection" by recognizing quoted string is data.

3. Heredoc/Inline Script AST Scanning

Command → Tier 1: Trigger (<100μs) → Tier 2: Extract (<1ms) → Tier 3: AST (<5ms)

Why clever: Catches python -c "import os; os.system('rm -rf /')" that would bypass regex.

4. Modular Pack System

Pack {
    id: "core.git",
    keywords: &["git"],  // Quick-reject gate
    safe_patterns: vec![/* git checkout -b is safe */],
    destructive_patterns: vec![/* git reset --hard is blocked */],
}

Why clever: Packs are keyword-gated. Kubernetes pack only activates if kubectl appears.


Dependencies

Package Why
fancy-regex + regex Pattern matching with lookbehind support
aho-corasick + memchr SIMD multi-pattern string matching
ast-grep-core Tree-sitter AST parsing for heredocs
serde + serde_json Hook protocol serialization
clap CLI parsing
rusqlite Local telemetry database
ratatui TUI output

Claude Code Integration (How Prevention Works)

The Flow

┌─────────────────┐     JSON Request      ┌─────────────────┐
│   Claude Code   │ ──────────────────────▶│       dcg       │
│                 │  {tool: "Bash",        │   (hook.rs)     │
│  wants to run:  │   command: "git        │                 │
│  git reset      │   reset --hard"}       │  evaluates...   │
│  --hard         │                        │                 │
└─────────────────┘                        └────────┬────────┘
                                                    │
                         ◀──────────────────────────┘
                           JSON Response

When ALLOWED (silent)

// dcg returns nothing or empty - command proceeds

When BLOCKED (deny)

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "BLOCKED by dcg...",
    "ruleId": "core.git:reset-hard",
    "packId": "core.git",
    "severity": "critical",
    "allowOnceCode": "abc12",
    "remediation": {
      "safeAlternative": "git stash",
      "explanation": "git reset --hard discards all uncommitted changes...",
      "allowOnceCommand": "dcg allow-once abc12"
    }
  }
}

What User Sees in Claude Code

BLOCKED by dcg

Reason: Destructive git command that discards uncommitted changes

Rule: core.git:reset-hard

Command: git reset --hard

Safe alternative: git stash

If this operation is truly needed, ask the user for explicit 
permission and have them run the command manually.

To allow once: dcg allow-once abc12

Key Points

Aspect How It Works
Hook protocol Claude Code's PreToolUse hook - intercepts before execution
Decision "allow" = silent pass, "deny" = blocked with reason
Allow-once Short code (abc12) lets user bypass once if intentional
Remediation Suggests safer alternatives (e.g., git stash instead of reset --hard)
AI-friendly Returns ruleId, packId, severity so AI understands why

Installation for Claude Code

# Install dcg
curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/destructive_command_guard/master/install.sh" | bash -s -- --easy-mode

# dcg auto-registers as PreToolUse hook
# Every Bash command goes through dcg before execution

# Test manually:
echo '{"tool_name":"Bash","tool_input":{"command":"git reset --hard"}}' | dcg hook

The magic: Claude Code never executes the command if dcg returns "deny". It just shows the block message to the user.


Links


Relevance to Nat-s-Agents

This is exactly what we need for multi-agent safety! Could integrate with:

  • MAW (Multi-Agent Workflow) as safety layer
  • Oracle as pattern repository for custom rules
  • Claude Code hooks in our workflow

Potential: Fork and add Oracle-aware patterns, sync with our philosophy of "Nothing is Deleted" (prevent destructive commands that violate this).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment