How dcg's Quick Rejection Filter Achieves Sub-Millisecond Performance
The dcg quick rejection filter achieves sub-millisecond performance by using SIMD-accelerated substring search via the memchr crate to eliminate ~99% of harmless commands before any regex compilation occurs.
The destructive_command_guard (dcg) repository implements a safety guard that intercepts every Bash command passed to Claude Code. To prevent the guard from becoming a bottleneck in interactive shell sessions, dcg's quick rejection filter employs a two-stage pipeline that processes the overwhelming majority of commands without invoking heavy regular expression engines or allocating heap memory.
The Two-Stage Filtering Architecture
To keep latency under one millisecond, dcg splits command evaluation into distinct hot and cold paths. This design ensures that common, safe commands exit the pipeline almost instantly, while only suspicious inputs trigger expensive analysis.
Stage 1: Keyword Quick-Reject (The Hot Path)
The quick-reject stage acts as a high-speed gatekeeper. It performs a SIMD-accelerated substring search using the memchr crate's memchr::memmem::Finder, which leverages SSE/AVX instructions to scan byte slices in a single pass. Because this operation requires zero heap allocation and runs in sub-microsecond time, it can evaluate whether a command contains any keywords associated with destructive operations (such as git or rm from the core.git and core.filesystem packs) before the regex engine initializes.
Stage 2: Full Pattern Evaluation
Only commands that pass the keyword check—indicating they might be destructive—proceed to the second stage. Here, dcg applies full whitelist/blacklist regex matching and sophisticated semantic analysis. By filtering out ~99% of safe commands in stage one, the system ensures the expensive regex path rarely executes, preserving overall throughput.
Implementation Details
The sub-millisecond guarantee relies on specific implementation choices in the Rust source code that prioritize cache efficiency and zero-allocation patterns.
SIMD-Accelerated Substring Search with memchr
Each core pack (core.git, core.filesystem, etc.) supplies a static list of keywords that any dangerous command in that category must contain. These keywords are compiled into memchr::memmem::Finder instances at build time. When a command arrives, the finder executes a SIMD-based scan across the raw bytes, returning an index if a keyword matches or none if the command is irrelevant. This approach avoids the branching overhead and complex state machines typical of regex engines.
The pack_aware_quick_reject Function
The central dispatch logic resides in src/packs/mod.rs near line 2509 in the pack_aware_quick_reject function. This function delegates to pack_aware_quick_reject_with_normalized, which performs the search on a trimmed command slice. The implementation iterates over the enabled pack keywords and returns true (indicating a quick reject) only when no keyword is found, meaning the command can be immediately marked as safe.
Zero-Allocation API
The quick-reject pipeline maintains its speed through a strict zero-allocation API. All data structures—including the Finder instances and keyword arrays—are declared as const or static. The compiler inlines these into the binary, eliminating runtime heap allocation and garbage collection pressure. The function operates entirely on &str slices, ensuring the hot path never triggers memory allocation.
Command Normalization and Diagnostics
Before the SIMD scan executes, commands undergo lightweight normalization in src/normalize.rs to strip leading paths like /usr/bin/git, ensuring the keyword search operates on canonical command names. Even when a command is fast-rejected, dcg records the decision via the TraceDetails::KeywordGating struct defined in src/trace.rs, capturing telemetry without adding measurable overhead to the fast path.
Performance Guarantees
The repository explicitly documents its performance budget in src/perf.rs at line 319:
/// 10 ms is enough for the fast path (quick-reject + safe pattern matching)
However, empirical benchmarks in benches/hook_latency.rs demonstrate that the quick-reject stage consistently completes in ≤ 0.5 ms for typical commands such as ls, cat, or git status. This provides ample headroom below the sub-millisecond target, ensuring the guard remains invisible to users during interactive shell sessions.
Practical Usage Example
The quick-reject logic integrates directly into dcg's evaluation flow:
use dcg::packs::{REGISTRY, pack_aware_quick_reject};
fn main() {
// Keywords derived from enabled packs (e.g., "git", "rm", "dd")
let keywords = &["git", "rm"];
// Command contains a keyword → requires full evaluation
assert!(!pack_aware_quick_reject("git status", keywords));
// Command contains no keywords → rejected instantly (safe)
assert!(pack_aware_quick_reject("ls -la", keywords));
}
When invoked from the command line, dcg exposes this behavior through the explain subcommand:
$ dcg explain "git status"
# → Keyword detected, proceeds to full pattern matching
$ dcg explain "echo hello"
# → Quick-rejected (no destructive keywords), exits in <1ms
Summary
- dcg's quick rejection filter uses a two-stage pipeline where SIMD-accelerated substring search eliminates ~99% of safe commands before regex evaluation.
- The implementation in
src/packs/mod.rsleverages thememchrcrate'smemchr::memmem::Finderto perform single-pass, allocation-free scans using SSE/AVX instructions. - Zero-allocation guarantees are maintained through static/const data structures and slice-based APIs that avoid heap memory.
- CI benchmarks in
benches/hook_latency.rsconfirm the quick-reject path completes in ≤ 0.5 ms, well within the sub-millisecond performance target. - Extending the filter with new packs only requires adding keywords to a static array, preserving the hot-path performance characteristics.
Frequently Asked Questions
How does dcg's quick rejection filter handle commands with absolute paths like /usr/bin/git?
The filter applies lightweight normalization via src/normalize.rs before executing the keyword search. This logic strips leading directory components from commands (e.g., converting /usr/bin/git to git), ensuring the SIMD substring search matches against canonical command names without path variations causing false negatives.
What percentage of commands does the quick rejection filter eliminate from full regex evaluation?
The quick-reject filter eliminates approximately 99% of typical shell commands. Because most interactive commands are harmless (such as ls, cat, or pwd), they contain no keywords associated with destructive packs and exit the pipeline immediately via the SIMD hot path, avoiding the expensive regex compilation and execution entirely.
Which Rust crate provides the SIMD acceleration for dcg's substring searches?
The memchr crate supplies the SIMD acceleration. Specifically, dcg uses memchr::memmem::Finder, which automatically detects and utilizes SSE/AVX instructions on x86_64 architectures to scan byte slices in a single pass, achieving sub-microsecond runtimes for the substring searches that power the quick-reject stage.
How does dcg maintain zero-allocation guarantees during the quick-reject phase?
The system declares all keyword finders and keyword arrays as const or static at compile time, storing them in the binary's read-only data section. The pack_aware_quick_reject function operates exclusively on stack-allocated &str slices and returns primitive booleans, ensuring the hot path never calls the allocator, which eliminates heap fragmentation and latency spikes.
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 →