- name
- dcg
- description
- Destructive Command Guard - High-performance Rust hook for Claude Code that blocks dangerous commands before execution. SIMD-accelerated, modular pack system, whitelist-first architecture. Essential safety layer for agent workflows.
# DCG — Destructive Command Guard
A high-performance Claude Code hook that intercepts and blocks destructive commands before they execute. Written in Rust with SIMD-accelerated filtering for sub-millisecond latency.
## Why This Exists
AI coding agents are powerful but fallible. They can accidentally run destructive commands:
- **"Let me clean up the build artifacts"** → `rm -rf ./src` (typo)
- **"I'll reset to the last commit"** → `git reset --hard` (destroys uncommitted changes)
- **"Let me fix the merge conflict"** → `git checkout -- .` (discards all modifications)
- **"I'll clean up untracked files"** → `git clean -fd` (permanently deletes untracked files)
DCG intercepts dangerous commands *before* execution and blocks them with a clear explanation, giving you a chance to stash your changes first.
## Critical Design Principles
### 1. Whitelist-First Architecture
Safe patterns are checked *before* destructive patterns. This ensures explicitly safe commands are never accidentally blocked:
```
git checkout -b feature → Matches SAFE "checkout-new-branch" → ALLOW
git checkout -- file.txt → No safe match, matches DESTRUCTIVE → DENY
```
### 2. Fail-Safe Defaults (Default-Allow)
Unrecognized commands are **allowed by default**. This ensures:
- The hook never breaks legitimate workflows
- Only *known* dangerous patterns are blocked
- New git commands work until explicitly categorized
### 3. Zero False Negatives Philosophy
The pattern set prioritizes **never allowing dangerous commands** over avoiding false positives. A few extra prompts for manual confirmation are acceptable; lost work is not.
## What It Blocks
### Git Commands That Destroy Uncommitted Work
| Command | Reason |
|---------|--------|
| `git reset --hard` | Destroys uncommitted changes |
| `git reset --merge` | Destroys uncommitted changes |
| `git checkout -- <file>` | Discards file modifications |
| `git restore <file>` (without `--staged`) | Discards uncommitted changes |
| `git clean -f` | Permanently deletes untracked files |
### Git Commands That Destroy Remote History
| Command | Reason |
|---------|--------|
| `git push --force` / `-f` | Overwrites remote commits |
| `git branch -d`, `--delete`, `-D`, `-f`, `-M`, `-C` | Deletes or force-overwrites a user-owned branch ref |
### Git Commands That Destroy Stashed Work
| Command | Reason |
|---------|--------|
| `git stash drop` | Permanently deletes a stash |
| `git stash clear` | Permanently deletes all stashes |
### Filesystem Commands
| Command | Reason |
|---------|--------|
| `rm -rf` (outside `/tmp`, `/var/tmp`, `$TMPDIR`) | Recursive deletion is dangerous |
## What It ALLOWS
Safe operations pass through silently:
### Always Safe Git Operations
`git status`, `git log`, `git diff`, `git add`, `git commit`, `git push`, `git pull`, `git fetch`, read-only branch listings, `git stash`, `git stash pop`, `git stash list`
### Explicitly Safe Patterns
| Pattern | Why Safe |
|---------|----------|
| `git checkout -b <branch>` | Creating new branches |
| `git checkout --orphan <branch>` | Creating orphan branches |
| `git restore --staged <file>` | Unstaging only, doesn't touch working tree |
| `git restore -S <file>` | Short flag for staged |
| `git clean -n` / `--dry-run` | Preview mode, no actual deletion |
| `rm -rf /tmp/*` | Temp directories are ephemeral |
| `rm -rf $TMPDIR/*` | Shell variable forms |
### Safe Alternative: `--force-with-lease`
```bash
git push --force-with-lease # ALLOWED - refuses if remote has unseen commits
git push --force # BLOCKED - can overwrite others' work
```
## Modular Pack System
DCG uses a modular "pack" system to organize patterns by category:
### Core Packs (Always Enabled)
| Pack | Description |
|------|-------------|
| `core.git` | Destructive git commands |
| `core.filesystem` | Dangerous rm -rf outside temp |
### Database Packs
| Pack | Description |
|------|-------------|
| `database.postgresql` | DROP/TRUNCATE in PostgreSQL |
| `database.mysql` | DROP/TRUNCATE in MySQL/MariaDB |
| `database.mongodb` | dropDatabase, drop() |
| `database.redis` | FLUSHALL/FLUSHDB |
| `database.sqlite` | DROP in SQLite |
### Container Packs
| Pack | Description |
|------|-------------|
| `containers.docker` | docker system prune, docker rm -f |
| `containers.compose` | docker-compose down --volumes |
| `containers.podman` | podman system prune |
### Kubernetes Packs
| Pack | Description |
|------|-------------|
| `kubernetes.kubectl` | kubectl delete namespace |
| `kubernetes.helm` | helm uninstall |
| `kubernetes.kustomize` | kustomize delete patterns |
### Cloud Provider Packs
| Pack | Description |
|------|-------------|
| `cloud.aws` | Destructive AWS CLI commands |
| `cloud.gcp` | Destructive gcloud commands |
| `cloud.azure` | Destructive az commands |
### Infrastructure Packs
| Pack | Description |
|------|-------------|
| `infrastructure.terraform` | terraform destroy |
| `infrastructure.ansible` | Dangerous ansible patterns |
| `infrastructure.pulumi` | pulumi destroy |
### System Packs
| Pack | Description |
|------|-------------|
| `system.disk` | dd, mkfs, fdisk operations |
| `system.permissions` | Dangerous chmod/chown patterns |
| `system.services` | systemctl stop/disable patterns |
### Other Packs
| Pack | Description |
|------|-------------|
| `strict_git` | Extra paranoid git protections |
| `package_managers` | npm unpublish, cargo yank |
### Configuring Packs
```toml
# ~/.config/dcg/config.toml
[packs]
enabled = [
"database.postgresql",
"containers.docker",
"kubernetes", # Enables all kubernetes sub-packs
]
```
## Environment Variables
| Variable | Description |
|----------|-------------|
| `DCG_PACKS="containers.docker,kubernetes"` | Enable packs (comma-separated) |
| `DCG_DISABLE="kubernetes.helm"` | Disable packs/sub-packs |
| `DCG_VERBOSE=1` | Verbose output |
| `DCG_COLOR=auto\|always\|never` | Color mode |
| `DCG_BYPASS=1` | Bypass DCG entirely (escape hatch) |
## Installation
### Quick Install (Verified Release)
Install `minisign` through your trusted OS package manager first (for example,
`apt install minisign` or `brew install minisign`). Then paste this function into
**Bash**. It authenticates the release installer with the project's pinned
Minisign key and checks its fixed SHA-256 identity before executing any downloaded
code. The key is the trust root; establish it from a trusted copy of this
documentation or an independent maintainer channel, not from the same download
as the installer. A downloaded checksum alone does not authenticate a publisher.
<!-- verified-release-install:begin -->
```bash
dcg_install() (
# Explicit failure guards also work when called inside `if dcg_install ...`.
set -eu
umask 077
if [ "$#" -gt 1 ]; then
printf '%s\n' 'Usage: dcg_install [--easy-mode|--system]' >&2
exit 1
fi
case "${1:-}" in
''|--easy-mode|--system) ;;
*) printf '%s\n' 'Usage: dcg_install [--easy-mode|--system]' >&2; exit 1 ;;
esac
readonly dcg_tag='v0.16.0'
readonly dcg_sha256='072462974ad790008e8a3aadb1a9eecf2d9b6bd0ef7b469f69f0fb0fa3b51c7c'
readonly dcg_key='RWSoYi6NXJWzaRs1mJmOwwXrZfPWcq6MXnQlNMLBYKzlIQTLwuVQG6uO'
dcg_minisign=$(type -P minisign) || {
printf '%s\n' 'Install minisign with your trusted OS package manager first.' >&2
exit 1
}
dcg_curl=$(type -P curl) || exit 1
dcg_bash=$(type -P bash) || exit 1
if dcg_hash=$(type -P sha256sum); then
dcg_hash_kind=sha256sum
elif dcg_hash=$(type -P shasum); then
dcg_hash_kind=shasum
else
printf '%s\n' 'A SHA-256 verifier (sha256sum or shasum) is required.' >&2
exit 1
fi
dcg_tmp=$(mktemp -d "${TMPDIR:-/tmp}/dcg-install.XXXXXXXXXX") || exit 1
printf 'Installer verification files: %s\n' "$dcg_tmp"
dcg_base="https://github.com/Dicklesworthstone/destructive_command_guard/releases/download/$dcg_tag"
for dcg_asset in install.sh install.sh.minisig; do
"$dcg_curl" --proto '=https' --proto-redir '=https' --tlsv1.2 -fsSL \
--max-time 120 --user-agent 'destructive_command_guard-installer' \
"$dcg_base/$dcg_asset" -o "$dcg_tmp/$dcg_asset" || exit 1
done
"$dcg_minisign" -Vm "$dcg_tmp/install.sh" \
-x "$dcg_tmp/install.sh.minisig" -P "$dcg_key" || exit 1
if [ "$dcg_hash_kind" = sha256sum ]; then
dcg_actual=$("$dcg_hash" "$dcg_tmp/install.sh") || exit 1
else
dcg_actual=$("$dcg_hash" -a 256 "$dcg_tmp/install.sh") || exit 1
fi
if [ "${dcg_actual%% *}" != "$dcg_sha256" ]; then
printf '%s\n' 'Installer does not match the pinned release; refusing execution.' >&2
exit 1
fi
case "${1:-}" in
--system)
# The first elevated command runs only after BOTH checks succeed.
sudo -- "$dcg_bash" "$dcg_tmp/install.sh" \
--version "$dcg_tag" --require-minisign --system ;;
--easy-mode)
"$dcg_bash" "$dcg_tmp/install.sh" \
--version "$dcg_tag" --require-minisign --easy-mode ;;
*) "$dcg_bash" "$dcg_tmp/install.sh" \
--version "$dcg_tag" --require-minisign ;;
esac
)
```
<!-- verified-release-install:end -->
Choose **one** installation mode after defining the function:
```bash
dcg_install # Normal: install to ~/.local/bin
dcg_install --easy-mode # Also configure PATH automatically
dcg_install --system # Install to /usr/local/bin using sudo after verification
```
For system-wide installation, install `minisign` on the system PATH so the
elevated installer can also verify the binary archive. Missing tools, missing
assets, invalid signatures, or a different installer digest stop installation;
there is no unsigned or source-build fallback. The private download directory is
retained for inspection. The tag and digest are a pair: upgrading this recipe
requires independently verifying and pinning the new release's installer bytes.
Do not replace the tag with `main` or `latest` or remove either verification.
For native Windows, follow the [verified PowerShell workflow](docs/windows.md#verified-release-installation).
### From Source (Requires Rust Nightly)
For development, build from a trusted, reviewed local checkout. This uses the
checkout's pinned toolchain and lockfile; it is a separate source-trust decision,
not a fallback when release authentication fails.
```bash
cargo install --path . --locked
```
### Prebuilt Binaries
Available for: Linux x86_64, Linux ARM64, macOS Intel, macOS Apple Silicon, Windows
## Claude Code Configuration
Add to `~/.claude/settings.json`:
```json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash|PowerShell|Monitor",
"hooks": [
{
"type": "command",
"command": "/absolute/path/to/dcg"
}
]
}
]
}
}
```
Ver no GitHub