dcg について
dcg は、AI コーディングエージェントが実行する前に既知の破壊的コマンドを検出する、Rust 製の安全フックです。安全なパターンを先に照合し、未認識のコマンドは許可する設計で、保護ルールをパック単位で設定できます。
主な機能
- 01危険な Git・ファイル操作の遮断
- 02データベースやクラウドのルールパック
- 03破壊的操作より安全パターンを優先
- 04未認識のコマンドはデフォルトで許可
- 05遮断理由と代替案の提示
活用シーン
- 01未コミットの Git 変更の破棄を防止
- 02ファイルや保存データの誤削除を回避
- 03コンテナ、Kubernetes、クラウドの破壊的操作を制限
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ dicklesworthstone/ destructive_command_guard --skill dcgインストール後、Claude Code で/dcgを入力して読み込まれたか確認します。
詳細
DCG — 破壊的コマンドガード
破壊的なコマンドが実行される前に検知してブロックする、高性能な Claude Code フックです。Rust で記述され、SIMD による高速フィルタリングでサブミリ秒のレイテンシーを実現します。
これが必要な理由
AI コーディングエージェントは強力ですが、誤りを犯すこともあります。誤って破壊的なコマンドを実行してしまうことがあります。
- 「ビルド成果物を整理しましょう」 →
rm -rf ./src(タイプミス) - 「最後のコミットまでリセットします」 →
git reset --hard(未コミットの変更を破棄) - 「マージコンフリクトを解決しましょう」 →
git checkout -- .(すべての変更を破棄) - 「未追跡ファイルを整理します」 →
git clean -fd(未追跡ファイルを完全に削除)
DCG は危険なコマンドが実行される前に検知してブロックし、変更を先に退避できるよう、明確な説明を表示します。
重要な設計原則
1. ホワイトリスト優先のアーキテクチャ
安全なパターンは、破壊的なパターンよりも先に確認されます。これにより、安全だと明示されたコマンドが誤ってブロックされることはありません。
git checkout -b feature → Matches SAFE "checkout-new-branch" → ALLOW
git checkout -- file.txt → No safe match, matches DESTRUCTIVE → DENY
2. フェイルセーフな既定値(既定では許可)
認識されないコマンドは、既定で許可されます。これにより、次のことが保証されます。
- フックが正当なワークフローを妨げることはありません
- 既知の危険なパターンだけがブロックされます
- 新しい git コマンドは、明示的に分類されるまでは動作します
3. 偽陰性ゼロの方針
パターンセットでは、偽陽性を避けることよりも、危険なコマンドを決して許可しないことを優先します。手動確認を求めるプロンプトが多少増えるのは許容できますが、作業が失われるのは許容できません。
ブロック対象
未コミットの作業を破棄する Git コマンド
| コマンド | 理由 |
|---|---|
git reset --hard | 未コミットの変更を破棄します |
git reset --merge | 未コミットの変更を破棄します |
git checkout -- <file> | ファイルの変更を破棄します |
git restore <file>(--staged を指定しない場合) | 未コミットの変更を破棄します |
git clean -f | 未追跡ファイルを完全に削除します |
リモートの履歴を破棄する Git コマンド
| コマンド | 理由 |
|---|---|
git push --force / -f | リモートのコミットを上書きします |
git branch -d、--delete、-D、-f、-M、-C | ユーザー所有のブランチ参照を削除または強制上書きします |
スタッシュした作業を破棄する Git コマンド
| コマンド | 理由 |
|---|---|
git stash drop | スタッシュを完全に削除します |
git stash clear | すべてのスタッシュを完全に削除します |
ファイルシステムコマンド
| コマンド | 理由 |
|---|---|
rm -rf(/tmp、/var/tmp、$TMPDIR の外) | 再帰的な削除は危険です |
許可されるコマンド
安全な操作は、何も表示せずに実行されます。
常に安全な Git 操作
git status、git log、git diff、git add、git commit、git push、git pull、git fetch、読み取り専用のブランチ一覧表示、git stash、git stash pop、git stash list
明示的に安全なパターン
| パターン | 安全な理由 |
|---|---|
git checkout -b <branch> | 新しいブランチを作成します |
git checkout --orphan <branch> | 孤立ブランチを作成します |
git restore --staged <file> | ステージングを解除するだけで、作業ツリーには触れません |
git restore -S <file> | ステージング用の短縮フラグです |
git clean -n / --dry-run | プレビューモードで、実際には削除しません |
rm -rf /tmp/* | 一時ディレクトリは一時的なものです |
rm -rf $TMPDIR/* | シェル変数を使った形式です |
安全な代替手段:--force-with-lease
git push --force-with-lease # ALLOWED - refuses if remote has unseen commits
git push --force # BLOCKED - can overwrite others' work
モジュール式パックシステム
DCG は、パターンをカテゴリ別に整理するために、モジュール式の「パック」システムを使用します。
コアパック(常に有効)
| パック | 説明 |
|---|---|
core.git | 破壊的な git コマンド |
core.filesystem | 一時領域以外での危険な rm -rf |
データベースパック
| パック | 説明 |
|---|---|
database.postgresql | PostgreSQL での DROP/TRUNCATE |
database.mysql | MySQL/MariaDB での DROP/TRUNCATE |
database.mongodb | dropDatabase、drop() |
database.redis | FLUSHALL/FLUSHDB |
database.sqlite | SQLite での DROP |
コンテナパック
| パック | 説明 |
|---|---|
containers.docker | docker system prune、docker rm -f |
containers.compose | docker-compose down --volumes |
containers.podman | podman system prune |
Kubernetes パック
| パック | 説明 |
|---|---|
kubernetes.kubectl | kubectl delete namespace |
kubernetes.helm | helm uninstall |
kubernetes.kustomize | kustomize delete パターン |
クラウドプロバイダーパック
| パック | 説明 |
|---|---|
cloud.aws | 破壊的な AWS CLI コマンド |
cloud.gcp | 破壊的な gcloud コマンド |
cloud.azure | 破壊的な az コマンド |
インフラストラクチャパック
| パック | 説明 |
|---|---|
infrastructure.terraform | terraform destroy |
infrastructure.ansible | 危険な ansible パターン |
infrastructure.pulumi | pulumi destroy |
システムパック
| パック | 説明 |
|---|---|
system.disk | dd、mkfs、fdisk 操作 |
system.permissions | 危険な chmod/chown パターン |
system.services | systemctl stop/disable パターン |
その他のパック
| パック | 説明 |
|---|---|
strict_git | 追加の paranoid な git 保護 |
package_managers | npm unpublish、cargo yank |
パックの設定
# ~/.config/dcg/config.toml
[packs]
enabled = [
"database.postgresql",
"containers.docker",
"kubernetes", # Enables all kubernetes sub-packs
]
環境変数
| 変数 | 説明 |
|---|---|
DCG_PACKS="containers.docker,kubernetes" | パックを有効化(カンマ区切り) |
DCG_DISABLE="kubernetes.helm" | パック/サブパックを無効化 |
DCG_VERBOSE=1 | 詳細出力 |
DCG_COLOR=auto|always|never | カラーモード |
DCG_BYPASS=1 | DCG を完全にバイパス(エスケープハッチ) |
インストール
クイックインストール(推奨)
curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/destructive_command_guard/main/install.sh?$(date +%s)" | bash
# Easy mode: auto-update PATH
curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/destructive_command_guard/main/install.sh?$(date +%s)" | bash -s -- --easy-mode
# System-wide (requires sudo)
curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/destructive_command_guard/main/install.sh?$(date +%s)" | sudo bash -s -- --system
ソースから(Rust Nightly が必要)
cargo +nightly install --git https://github.com/Dicklesworthstone/destructive_command_guard
ビルド済みバイナリ
対応: Linux x86_64、Linux ARM64、macOS Intel、macOS Apple Silicon、Windows
Claude Code の設定
~/.claude/settings.json に追加します:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash|PowerShell|Monitor",
"hooks": [
{
"type": "command",
"command": "/absolute/path/to/dcg"
}
]
}
]
}
}
/absolute/path/to/dcg は実際に解決されたバイナリパスに置き換えてください。裸の dcg は使用しないでください。非対話型のフックシェルは対話型の PATH を継承しない可能性があります。ネイティブ Windows では、install.ps1 を使用して、フックが PowerShell セーフな絶対コマンドと明示的なシェル選択を受け取るようにしてください。
重要: フックを追加した後、Claude Code を再起動してください。
仕組み
処理パイプライン
┌─────────────────────────────────────────────────────────────────┐
│ Claude Code │
│ Agent executes `rm -rf ./build` │
└─────────────────────┬───────────────────────────────────────────┘
│
▼ PreToolUse hook (stdin: JSON)
┌─────────────────────────────────────────────────────────────────┐
│ dcg │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Parse │───▶│ Normalize │───▶│ Quick Reject │ │
│ │ JSON │ │ Command │ │ Filter │ │
│ └──────────────┘ └──────────────┘ └──────┬───────┘ │
│ │ │
│ ┌───────────────────────────┘ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Pattern Matching │ │
│ │ 1. Check SAFE_PATTERNS (whitelist) ──▶ Allow if match │ │
│ │ 2. Check DESTRUCTIVE_PATTERNS ──────▶ Deny if match │ │
│ │ 3. No match ────────────────────────▶ Allow (default) │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────┬───────────────────────────────────────────┘
│
▼ stdout: JSON (deny) or empty (allow)
ステージ 1: JSON 解析
- stdin からフック入力を受け取ります
- Claude Code の
PreToolUseフォーマットを検証します - Bash 以外のツールは即座に許可されます
ステージ 2: コマンドの正規化
- 絶対パスを除去します:
/usr/bin/git status→git status - 引数のパスは保持します
ステージ 3: クイック拒否フィルター
- "git" または "rm" に対する SIMD 加速された部分文字列検索
- これらを含まないコマンドは正規表現を完全にバイパスします(コマンドの 99% 以上)
ステージ 4: パターンマッチング
- 安全なパターンを先にチェックします(マッチしたら短絡して許可)
- 破壊的なパターンを次にチェックします(マッチしたら拒否)
- マッチしない場合はデフォルトで許可
終了コード
| コード | 意味 |
|---|---|
0 | コマンドは安全です。続行します |
2 | コマンドはブロックされました。実行しないでください |
CLI の使用法
コマンドを手動でテストします:
# Show version with build metadata
dcg --version
# Test a command
echo '{"tool_name":"Bash","tool_input":{"command":"git reset --hard"}}' | dcg
ブロックメッセージの例
════════════════════════════════════════════════════════════════════════
BLOCKED dcg
────────────────────────────────────────────────────────────────────────
Reason: git reset --hard destroys uncommitted changes. Use 'git stash' first.
Command: git reset --hard HEAD~1
Tip: If you need to run this command, execute it manually in a terminal.
Consider using 'git stash' first to save your changes.
════════════════════════════════════════════════════════════════════════
状況に応じた提案
| コマンドの種類 | 提案 |
|---|---|
git reset、git checkout -- | 「先に 'git stash' の使用を検討してください」 |
git clean | 「先に 'git clean -n' でプレビューしてください」 |
git push --force | 「'--force-with-lease' の使用を検討してください」 |
rm -rf | 「手動で実行する前にパスを慎重に確認してください」 |
対応するエッジケース
パスの正規化
/usr/bin/git reset --hard # Blocked
/usr/local/bin/git checkout -- . # Blocked
/bin/rm -rf /home/user # Blocked
フラグの順序バリエーション
rm -rf /path # Combined flags
rm -fr /path # Reversed order
rm -r -f /path # Separate flags
rm --recursive --force /path # Long flags
すべてのバリエーションに対応しています。
シェル変数の展開
rm -rf $TMPDIR/build # Allowed (temp)
rm -rf ${TMPDIR}/build # Allowed
rm -rf "$TMPDIR/build" # Allowed
rm -rf "${TMPDIR:-/tmp}/build" # Allowed
ステージ済みとワークツリーの復元
git restore --staged file.txt # Allowed (unstaging only)
git restore -S file.txt # Allowed (short flag)
git restore file.txt # BLOCKED (discards changes)
git restore --worktree file.txt # BLOCKED (explicit worktree)
git restore -S -W file.txt # BLOCKED (includes worktree)
パフォーマンスの最適化
DCG は、遅延を意識させないように設計されています。
| 最適化 | 手法 |
|---|---|
| Lazy Static | LazyLock を使って正規表現パターンを一度だけコンパイル |
| SIMD Quick Reject | memchr クレートで CPU のベクトル命令を使用 |
| Early Exit | 安全な一致が見つかると直ちに終了 |
| Zero-Copy JSON | serde_json が入力バッファーを直接処理 |
| Zero-Allocation | パスの正規化に Cow<str> を使用 |
| Release Profile | opt-level="z"、LTO、単一のコード生成ユニット |
結果: 通常のコマンドを 1 ミリ秒未満で実行します。
パターン数
| 種類 | 数 |
|---|---|
| 安全なパターン(許可リスト) | 34 |
| 破壊的なパターン(拒否リスト) | 16 |
セキュリティに関する考慮事項
DCG が防ぐもの
git checkout --やgit reset --hardによる偶発的なデータ損失- 強制プッシュによるリモート履歴の破壊
git stash drop/clearによるスタッシュの損失- 一時ディレクトリ外での
rm -rfによるファイルシステム上の事故
DCG が防がないもの
- 悪意のある攻撃者(フックを回避できます)
- Bash 以外のコマンド(Python/JavaScript によるファイル書き込み、API 呼び出し)
- コミット済みで未プッシュの作業
- スクリプト内のコマンド(
./deploy.shの内容は検査されません)
脅威モデル
DCG は、AI エージェントが善意ではあるが誤りを犯しうると想定しています。悪意ある攻撃ではなく、意図しないミスを検出します。
トラブルシューティング
フックがコマンドをブロックしない
~/.claude/settings.jsonにフック設定があることを確認します- Claude Code を再起動します
- 手動でテストします:
echo '{"tool_name":"Bash","tool_input":{"command":"git reset --hard"}}' | dcg
フックが安全なコマンドをブロックする
- 対応されていないエッジケースがないか確認します
- GitHub のイシューを作成します
- 一時的に回避します:
DCG_BYPASS=1を設定するか、コマンドを手動で実行します
FAQ
Q: なぜ git branch -d と git branch -D の両方をブロックするのですか?
小文字の -d はマージ状態を確認しますが、それでもブランチ名、上流追跡設定、便利な reflog 参照を削除します。これらはユーザーが所有する状態であるため、どの形式の削除にも明示的な承認が必要です。まず git branch -vv、git branch --merged、git branch --no-merged で確認してください。マージ状態を確認する形式には専用のルール core.git:branch-delete があるため、[policy.rules] "core.git:branch-delete" = "ask" を設定すると承認プロンプトが表示されます。一方、-D(core.git:branch-force-delete)は引き続き拒否されます。
Q: なぜ git push --force-with-lease は許可されるのですか?
Force-with-lease は、確認していないコミットがリモートにある場合、プッシュを拒否するため、誤って上書きすることを防ぎます。
Q: なぜ一時ディレクトリ外のすべての rm -rf をブロックするのですか?
再帰的な強制削除は非常に危険です。入力ミスや誤った変数によって、重要なファイルが削除される可能性があります。一時ディレクトリは、データが一時的にのみ存在することを前提に設計されています。
Q: ブロックされたコマンドをどうしても実行する必要がある場合はどうすればよいですか?
DCG はエージェントに許可を求めるよう指示します。慎重に判断したうえで、別のターミナルからコマンドを手動で実行してください。
Flywheel との統合
| ツール | 統合 |
|---|---|
| Claude Code | ネイティブの PreToolUse フック |
| Agent Mail | エージェントはブロックされたコマンドをコーディネーターに報告できます |
| BV | DCG が繰り返しトリガーされるタスクにフラグを付けます |
| CASS | セッション全体から DCG のブロックパターンを検索します |
| RU | DCG は破壊的なコミットから agent-sweep を保護します |