仕組み
アーキテクチャ
ccchain は Claude Code の PreToolUse hook として動作します。Claude が Bash コマンドを実行しようとすると、実行前に ccchain が起動されます。
Claude がコマンドを実行しようとする
│
▼
┌──────────────────────┐
│ ccchain hook pre │
│ │
│ 1. シェル AST 解析 │ ← mvdan.cc/sh (bash モード)
│ 2. トポロジー構築 │ ← パイプ、チェーン、サブシェル
│ 3. ルール評価 │ ← .ccchain.conf
│ 4. 判定結果を返す │
└──────────────────────┘
│
┌────┴────┐
│ │
exit 0 exit 2
(許可) (拒否 + 理由メッセージ)
Claude はメッセージを読み
コマンドを自律的に書き直す評価フロー
1. シェル AST パース
mvdan.cc/sh(shfmt の内部パーサー)を bash モードで使用し、コマンド文字列を完全な AST に変換します。対応する構文:
- パイプ:
cmd1 | cmd2 - チェーン:
cmd1 && cmd2、cmd1 ; cmd2 - サブシェル:
$(cmd)、(cmd1; cmd2) - プロセス置換:
<(cmd) - リダイレクト:
cmd > file、cmd >> file
2. トポロジー構築
AST を実行トポロジーに変換します。これはコマンド間の関係に焦点を当てた簡略表現です:
&&、||、;で区切られたセグメント- 各セグメントはパイプライン(
|で接続)または単一コマンド find -exec、xargs、bash -c、evalのネストコマンドは再帰的にパース
3. ルール評価
各セグメントは DSL ルールに対して独立に評価されます:
- パイプラインの最初のコマンドはトップレベルルールでマッチ
- パイプされた後続コマンドは親コマンドの
|,>>コンテキストルールでマッチ - ネストコマンド(
-exec等)はexec:コンテキストルールでマッチ - last-rule-wins: 複数マッチ時は最後のルールが優先
- テンプレートチェーン(
next:、extends:)はマッチング時に展開
4. 判定出力
評価結果は5種類のアクションのいずれかを生成します:
| アクション | exit code | 効果 |
|---|---|---|
allow | 0 | コマンドが実行される |
deny | 2 + stderr メッセージ | コマンドがブロック、Claude に理由が伝わる |
warn | 0 + stdout JSON | コマンドは実行、Claude に警告が伝わる |
ask | 0 + {"decision":"ask"} | Claude Code の標準パーミッションダイアログに委譲 |
パフォーマンス
全処理はシングルバイナリ内のインメモリで完結します:
| 処理 | 所要時間 |
|---|---|
| シェル AST パース | ~2 μs |
| トポロジー構築 | ~9 μs |
| ルール評価 | ~3 μs |
| 合計(エンドツーエンド) | ~5 μs |
Claude Code の操作に体感できる遅延は一切ありません。
Fail-Open 設計
ccchain 自身のエラー(JSON パース失敗、設定ファイルエラー、シェルパースエラー)が発生した場合、コマンドは許可されます(exit 0)。これにより:
- ccchain のバグで Claude の操作が止まることがない
- エラーは stderr に出力されるため、デバッグ可能
- セキュリティより可用性を優先する設計判断(ccchain は「完璧なサンドボックス」ではなく「監査可能なセキュリティ」を目指す)