| name | hook-writing |
| description | Agent Hook(.json)の作成・編集を行う。hookイベント、matcher、入出力フォーマット、exit code、設置場所の設計を支援する。hook作成、hooks、PreToolUse、PostToolUse、SessionStart、Stop、.github/hooks、/hooks、agent hook、hookファイルなどの言及時に使用。 |
Hook Writing
Agent Hook の作成・編集ガイド。ライフサイクルイベントにシェルコマンドを紐づけて、セキュリティポリシーの適用、コード品質の自動化、監査などを実現する。
⚠️ よくある致命的なミス
-
❌ matcher を指定して特定ツールだけに適用しようとする
- VS Code は現在 matcher 値を無視する(全ツール/全イベントに適用される)
- ✅ Hook スクリプト内で
tool_name を自前フィルタリングする
-
❌ type: "prompt" や type: "agent" を使う
- これらは Claude Code 固有。VS Code は
type: "command" のみ対応
- ✅ 判断ロジックが必要なら、スクリプト内で実装する
-
❌ Stop hook で stop_hook_active チェックを忘れる
- 無限ループでエージェントが停止しなくなる
- ✅
stop_hook_active: true のとき exit 0 で即座に終了する
📋 ライフサイクルイベント(8種)
| イベント | タイミング | 用途例 |
|---|
SessionStart | セッション開始時 | プロジェクト情報注入、リソース初期化 |
UserPromptSubmit | プロンプト送信時 | リクエスト監査、コンテキスト注入 |
PreToolUse | ツール実行前 | 危険操作ブロック、承認制御 |
PostToolUse | ツール成功後 | フォーマッタ実行、ログ記録 |
PreCompact | コンテキスト圧縮前 | 重要コンテキストの退避 |
SubagentStart | サブエージェント起動時 | サブエージェントへのコンテキスト注入 |
SubagentStop | サブエージェント完了時 | 結果検証、リソースクリーンアップ |
Stop | セッション終了時 | レポート生成、通知送信 |
📂 設置場所
| パス | スコープ | 共有 | 備考 |
|---|
.agents/hooks/*.json | プロジェクト | ❌ ローカル | 推奨。エージェントが編集可能 |
.github/hooks/*.json | プロジェクト | ✅ チーム共有 | 編集せず提案のみ |
ワークスペースの hook がユーザーの hook より優先される。
🚀 新規 Hook 作成
Init スクリプトで Hook の雛形を生成し、ロジック実装に集中する。
.agents/skills/hook-writing/scripts/init_hook.sh <hook-name> <EventName>
.agents/skills/hook-writing/scripts/init_hook_script.sh <hook-name>
詳細な手順・手動作成方法・トラブルシューティングは 新規 Hook 作成手順 を参照。
📥 入出力フォーマット
入力(stdin)
イベントごとに以下のフィールドが JSON で渡される:
PreToolUse / PostToolUse: tool_name, tool_input, tool_use_id
PostToolUse: 上記 + tool_response
SessionStart: source(現在は常に "new")
Stop / SubagentStop: stop_hook_active
SubagentStart / SubagentStop: agent_id, agent_type
PreCompact: trigger
UserPromptSubmit: prompt
出力(stdout)
共通出力フォーマット:
{
"continue": true,
"stopReason": "理由(モデルに表示)",
"systemMessage": "メッセージ(ユーザーに表示)"
}
Exit code
| コード | 意味 |
|---|
0 | 成功。stdout を JSON としてパース |
2 | ブロック。stderr がモデルへのフィードバック |
| その他 | 非ブロック警告。stderr をログ、処理は続行 |
イベント別の hookSpecificOutput 詳細は イベント別出力リファレンス を参照。
⚡ VS Code 固有の制約
Claude Code と同じフォーマットだが、以下の制約に注意:
- matcher は無視される → スクリプト内で
tool_name を自前フィルタリング
type: "command" のみ → prompt/agent は使えない
- デフォルト timeout 30秒 → 重い処理は明示的に延長する
詳細な差分は VS Code vs Claude Code 差分チェックリスト を参照。
💡 推奨プラクティス
- タイムアウトは用途に応じて明示的に設定する(デフォルト30秒)
- 複雑なロジックは別スクリプトに切り出す
- JSON パースには
jq を使う
- stderr への出力は具体的で actionable にする(モデルへのフィードバックになるため)
💡 実装例
例1: 危険コマンドのブロック(PreToolUse)
.github/hooks/block-dangerous-commands.json:
{
"hooks": {
"PreToolUse": [
{
"type": "command",
"command": ".github/hooks/scripts/block-dangerous.sh",
"timeout": 10
}
]
}
}
.github/hooks/scripts/block-dangerous.sh:
#!/bin/bash
set -euo pipefail
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty')
if [[ "$TOOL_NAME" != "run_in_terminal" ]]; then
exit 0
fi
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
if echo "$COMMAND" | grep -qiE '(rm -rf /|drop table|truncate table)'; then
echo "Blocked: destructive command detected" >&2
exit 2
fi
exit 0
📚 参考資料
Hook はフォーマットを揃え、スクリプト内でツール名フィルタリングを徹底する。VS Code の matcher 未対応を常に意識すること。