Hooks を使うと、Qoder IDE や JetBrains プラグインの実行フローにおける重要なポイントで、コードを変更することなくカスタムロジックを挿入できます。JSON 設定ファイルを編集するだけで、たとえば次のようなことを実現できます。
- ツール実行前に危険な操作をブロック
- ファイル書き込みのたびに自動で lint を実行し、コードスタイルを統一
- Agent のタスク完了時にデスクトップ通知を送り、画面に張り付く必要をなくす
Prompt による指示とは異なり、Hooks は確定的に動作します。イベントが発火すればスクリプトは必ず実行され、モデルの解釈に結果が左右されることはありません。
サポートされるイベント
IDE / JB プラグインが現在サポートしている Hook イベントは以下の 5 種類です。
| イベント名 | 発火タイミング | ブロック可能 |
|---|
| UserPromptSubmit | ユーザーが Prompt を送信した後、Agent が処理を開始する前 | はい |
| PreToolUse | ツール実行の前 | はい |
| PostToolUse | ツール実行の成功後 | いいえ |
| PostToolUseFailure | ツール実行の失敗後 | いいえ |
| Stop | Agent がレスポンスを返し終えた時 | いいえ |
クイックスタート
以下の例では、rm -rf のような危険なコマンドをブロックする方法を紹介します。
スクリプトを作成
mkdir -p ~/.qoder/hooks
cat > ~/.qoder/hooks/block-rm.sh << 'EOF'
#!/bin/bash
input=$(cat)
command=$(echo "$input" | jq -r '.tool_input.command')
if echo "$command" | grep -q 'rm -rf'; then
echo "Dangerous command blocked: $command" >&2
exit 2
fi
exit 0
EOF
chmod +x ~/.qoder/hooks/block-rm.sh
設定を追加
~/.qoder/settings.json に以下を追加します。{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "~/.qoder/hooks/block-rm.sh"
}
]
}
]
}
}
動作を確認
IDE を開き、Qoder プラグインパネルで rm -rf を含むコマンドの実行を Agent に指示してください。Hook が実行をブロックし、エラーメッセージを Agent にフィードバックします。
ユースケース
| シナリオ | 対応イベント | 説明 |
|---|
| 危険コマンドの遮断 | PreToolUse | rm -rf や DROP TABLE などの実行前にブロック |
| ファイルパスの検証 | PreToolUse | 指定ディレクトリ内でのみファイルの作成・編集を許可 |
| 自動 Lint / フォーマット | PostToolUse | ファイル書き込みのたびに ESLint / Prettier を自動実行 |
| 監査ログ | PostToolUse | すべてのツール呼び出しを記録し、セキュリティ監査に活用 |
| 失敗時のモニタリング | PostToolUseFailure | ツール実行が失敗した際にアラートを送信、またはエラーログを記録 |
| Prompt の内容チェック | UserPromptSubmit | ユーザー入力に機密情報(パスワード、キーなど)が含まれていないか検出 |
| コンテキストの自動注入 | UserPromptSubmit | Prompt の末尾にプロジェクト規約やコーディング規約を自動付加 |
| デスクトップ通知 | Stop | Agent 完了時にシステム通知を表示 |
仕組み
Hook の利用は、スクリプトを書く → 設定に登録する → 自動で有効になる、という 3 ステップです。
Agent がライフサイクル上の特定のポイント(例: ツール呼び出し前)に到達すると、プラグインは該当するイベントに Hook が登録されているかを確認します。
- プラグインは起動時にすべての Hook 設定を読み込む
- Agent の実行中にイベントポイント(例:
PreToolUse)に到達する
- プラグインはそのイベントに登録された Hook グループを順に走査し、
matcher で現在のコンテキストと照合する
- マッチした Hook は登録順にシェルスクリプトを実行する
- スクリプトは
stdin からイベントコンテキスト(JSON)を受け取り、exit code と stdout で結果を返す
- プラグインはその結果に基づいて後続の動作(続行またはブロック)を決定する
前提条件
- jq: サンプルスクリプトでは JSON の解析に jq を使用しています。macOS では
brew install jq、Linux では apt install jq でインストールしてください。
- スクリプト権限: すべての Hook スクリプトに実行権限が必要です(
chmod +x)。
Hooks の作成
1. 要件の整理: イベントとマッチ範囲を決める
まず、どのタイミングで介入し、どの操作を対象にするかを明確にします。
「いつ」介入するか? 「どの操作」を対象にするか?
↓ ↓
イベントを選択 matcher を設定
| 要件 | イベント | matcher |
|---|
| Shell コマンド実行前にチェックしたい | PreToolUse | "Bash" |
| ファイルの書き込み・編集後に処理したい | PostToolUse | "Write|Edit" |
| ツール実行の失敗を記録したい | PostToolUseFailure | "Bash" または未指定 |
| すべての Prompt を審査したい | UserPromptSubmit | 未指定(すべてにマッチ) |
| Agent の停止時に通知したい | Stop | 未指定(すべてにマッチ) |
| MCP ツールのみ対象にしたい | PreToolUse | "mcp__.*" |
2. Hook スクリプトを書く
Hook スクリプトは標準的なシェルスクリプトで、以下の入出力規約に従います。
入力: stdin から JSON 形式のイベントコンテキストを受け取る
出力: exit code で動作を制御する
exit 0 → 続行(操作を許可)
exit 2 → ブロック(操作を停止し、stderr の内容を会話に注入)
それ以外 → エラー(操作は続行し、stderr をユーザーに表示)
スクリプトテンプレート:
#!/bin/bash
# 1. Read JSON input from stdin
input=$(cat)
# 2. Extract fields with jq
# Each event has different fields — see the "Hooks イベント" section
tool_name=$(echo "$input" | jq -r '.tool_name')
tool_input=$(echo "$input" | jq -r '.tool_input')
# 3. Implement your decision logic
if [ "$tool_name" = "Bash" ]; then
command=$(echo "$input" | jq -r '.tool_input.command')
# Check for dangerous operations
if echo "$command" | grep -qE 'rm\s+-rf|DROP\s+TABLE'; then
# Block: exit 2 + stderr message is fed back to Agent
echo "Operation denied: $command" >&2
exit 2
fi
fi
# 4. Allow
exit 0
exit code に加えて、exit 0 の際に JSON を出力することで、より細かい制御が可能です。#!/bin/bash
input=$(cat)
# Output JSON for fine-grained control (only parsed when exit 0)
echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"This operation is not allowed"}}'
exit 0
3. 設定ファイルへの登録
スクリプトのパスを、設定ファイルの該当イベントに記述します。
{
"hooks": {
"EventName": [
{
"matcher": "MatchPattern (optional)",
"hooks": [
{
"type": "command",
"command": "path/to/script"
}
]
}
]
}
}
4. テストとデバッグ
ターミナルでパイプを使って直接テストできます。
# Simulate a PreToolUse event
echo '{"tool_name":"Bash","tool_input":{"command":"rm -rf /"},"hook_event_name":"PreToolUse"}' \
| ~/.qoder/hooks/block-rm.sh
echo "Exit code: $?"
stderr 出力(ブロックメッセージ)を確認するには:
echo '{"tool_name":"Bash","tool_input":{"command":"rm -rf /"}}' \
| ~/.qoder/hooks/block-rm.sh 2>&1
Hooks の設定
設定ファイルの場所
Hook 設定は以下のファイルから読み込まれます。複数レベルの設定はマージされて実行されます(優先度の低い順)。
| パス | スコープ | 優先度 | 共有可能 | 説明 |
|---|
~/.qoder/settings.json | グローバル(ユーザー) | 1(最低) | いいえ | ユーザー個人の設定。すべてのプロジェクトに適用 |
.qoder/settings.json | プロジェクト | 2 | はい | Git にコミットしてチームで共有可能 |
.qoder/settings.local.json | プロジェクトローカル | 3 | いいえ | gitignore 対象。個人の開発用設定 |
IDE / JB プラグインと CLI は同じ設定ファイルを共有します。現在のバージョンではホットリロードに未対応のため、設定変更後は IDE の再起動が必要です。
設定フォーマット
{
"hooks": {
"EventName": [
{
"matcher": "MatchPattern",
"hooks": [
{
"type": "command",
"command": "command to execute"
}
]
}
]
}
}
| フィールド | 必須 | 説明 |
|---|
type | はい | "command" 固定 |
command | はい | 実行するシェルコマンドまたはスクリプトのパス |
timeout | いいえ | タイムアウト(秒)。デフォルトは 30 秒。現在のバージョンではカスタマイズ不可(次バージョンで対応予定) |
matcher | いいえ | マッチ条件。未指定の場合はそのイベントのすべてのトリガーにマッチ |
1 つのイベントに対して複数の matcher グループを設定でき、各グループには複数の Hook コマンドを含められます。
matcher マッチルール
matcher は Hook の発火対象を絞り込むために使用します。イベントごとにマッチ対象のフィールドが異なります(各イベントの説明を参照)。
| 記法 | 意味 | 例 |
|---|
未指定または "*" | すべてにマッチ | すべてのツールでトリガー |
| 完全一致の値 | 完全一致 | "Bash" は Bash ツールの時のみトリガー |
| 区切り | 複数の値にマッチ | "Write|Edit" は Write または Edit の時にトリガー |
| 正規表現 | 正規表現マッチ | "mcp__.*" はすべての MCP ツールにマッチ |
ツール名マッピング
Qoder はネイティブのツール名と Claude Code 互換のツール名の 2 セットをサポートしています。Hook の設定ではどちらでも使用でき、プラグイン内部で統一的にマッピングしてからマッチングを行います。たとえば matcher: "Bash" と matcher: "run_in_terminal" は同じ意味です。
| Qoder ネイティブ名 | 互換名 | 説明 |
|---|
run_in_terminal | Bash | シェルコマンドの実行 |
read_file | Read | ファイル内容の読み取り |
create_file | Write | ファイルの作成・書き込み |
search_replace | Edit | ファイルの編集 |
delete_file | - | ファイルの削除 |
grep_code | Grep | ファイル内容の検索 |
search_file | Glob | ファイル名のマッチング |
list_dir | LS | ディレクトリの一覧表示 |
task | Task | サブタスク / サブエージェントの起動 |
Skill | - | スキルの呼び出し |
search_web | WebSearch | Web 検索 |
fetch_content | WebFetch | Web コンテンツの取得 |
todo_write | TodoWrite | TODO の書き込み |
ask_user_question | - | ユーザーへの質問 |
search_memory | - | メモリの検索 |
update_memory | - | メモリの更新 |
switch_mode | - | モードの切り替え |
create_plan | - | プランの作成 |
run_preview | - | Web アプリのプレビュー |
mcp__<server>__<tool> | 同左 | MCP ツール |
Hook スクリプトの書き方
Hook スクリプトは stdin から JSON 入力を受け取り、exit code と stdout で動作を制御します。このセクションでは全イベント共通の入出力フォーマットを説明します。各イベント固有のフィールドについてはHooks イベントを参照してください。
Hook スクリプトは stdin から JSON データを受け取ります。すべてのイベントで共通するフィールドは以下のとおりです。
| フィールド | 説明 |
|---|
session_id | 現在のセッション ID |
cwd | 現在の作業ディレクトリ |
hook_event_name | トリガーされたイベント名 |
transcript_path | セッションコンテキスト JSON ファイルのパス |
イベントによっては、上記に加えて追加のフィールドが含まれます(各イベントの説明を参照)。
jq で入力を解析する例:
#!/bin/bash
input=$(cat)
tool_name=$(echo "$input" | jq -r '.tool_name')
Hook は exit code と stdout で動作を制御します。
exit code による基本動作:
| Exit Code | 意味 | 動作 |
|---|
0 | 成功 | 操作を続行し、stdout の JSON 解析を試みる |
2 | ブロック | 操作を停止し、stderr の内容を会話に注入(ブロック可能なイベントのみ有効) |
| その他 | エラー | 操作は続行するが、stderr をユーザーに表示 |
stdout JSON(exit 0 の場合のみ解析)を使うと、一部のイベントでより細かい制御が可能です。サポートされるフィールドの詳細は各イベントの説明を参照してください。exit code が 0 以外の場合、stdout は無視されます。
環境変数
Hook スクリプトの実行時に、プラグインがいくつかの環境変数を自動的に設定します。注入される環境変数の具体的なリストは今後確定予定です。
Hooks イベント
UserPromptSubmit
ユーザーが IDE プラグインパネルで Prompt を送信した後、Agent が処理を開始する前に発火します。Prompt の審査やコンテンツフィルタリング、コンテキストの自動補完などに利用できます。
matcher マッチ: マッチ対象のフィールドはなく、すべてのユーザー入力に対して一律に発火します。
追加入力フィールド:
{
"session_id": "abc-123",
"cwd": "/path/to/project",
"hook_event_name": "UserPromptSubmit",
"prompt": "Write a sort function for me"
}
Prompt 送信のブロック: exit code 2 を返すと、stderr の内容がエラーメッセージとしてユーザーに表示され、Agent はその Prompt を処理しません。
stdout JSON 出力フィールド(exit 0 の場合):
{
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": "## Current Git status\n..."
}
}
| フィールド | 型 | 説明 |
|---|
hookSpecificOutput.hookEventName | string | "UserPromptSubmit" 固定 |
hookSpecificOutput.additionalContext | string | 追加コンテキスト情報。Agent の会話に注入される |
例: Prompt にプロジェクト規約を自動付加
#!/bin/bash
input=$(cat)
prompt=$(echo "$input" | jq -r '.prompt')
# Automatically append coding standards reminder
echo '{"hookSpecificOutput":{"hookEventName":"UserPromptSubmit","additionalContext":"Please follow the coding standards in the project .editorconfig."}}'
exit 0
ツール実行前に発火します。ツールの実行をブロックできます。 最もよく使われるイベントで、危険コマンドの遮断やファイルパスの検証、権限チェックなどに適しています。
matcher マッチ: ツール名(Bash、Write、Edit、Read、Glob、Grep や、MCP ツール名 mcp__server__tool など)
追加入力フィールド:
{
"session_id": "abc-123",
"cwd": "/path/to/project",
"hook_event_name": "PreToolUse",
"tool_name": "Bash",
"tool_input": { "command": "rm -rf /tmp/build" }
}
ツール実行のブロック: exit code 2 を返すと、stderr の内容がエラーとして Agent に返されます。完全な例はクイックスタートを参照してください。
stdout JSON 出力フィールド(exit 0 の場合):
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow",
"permissionDecisionReason": "Safe read operation",
"updatedInput": { "command": "npm test --coverage" },
"additionalContext": "Added coverage flag"
}
}
| フィールド | 型 | 説明 |
|---|
hookSpecificOutput.hookEventName | string | "PreToolUse" 固定 |
hookSpecificOutput.permissionDecision | string | "allow"(許可)、"deny"(拒否)、"ask"(ユーザーに確認) |
hookSpecificOutput.permissionDecisionReason | string | 決定理由。deny や ask の場合に Agent またはユーザーに表示される |
hookSpecificOutput.updatedInput | object | 変更後のツール入力パラメータ(任意。ツールの呼び出し内容を書き換える場合に使用) |
hookSpecificOutput.additionalContext | string | 追加コンテキスト情報(任意) |
PostToolUse
ツール実行の成功後に発火します。ブロックはできません。自動 lint やログ記録、結果の分析などに適しています。
matcher マッチ: ツール名
追加入力フィールド:
{
"session_id": "abc-123",
"cwd": "/path/to/project",
"hook_event_name": "PostToolUse",
"tool_name": "Write",
"tool_input": { "file_path": "/path/to/file.ts", "content": "..." },
"tool_response": "File written successfully"
}
stdout JSON 出力フィールド(exit 0 の場合):
{
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"feedback": "File formatted with Prettier. 3 issues auto-fixed."
}
}
| フィールド | 型 | 説明 |
|---|
hookSpecificOutput.hookEventName | string | "PostToolUse" 固定 |
hookSpecificOutput.feedback | string | フィードバック情報。ユーザーに表示される(例: lint 結果のサマリー) |
PostToolUseFailure
ツール実行の失敗後に発火します。ブロックはできません。エラーの監視やリトライの提案、ログ記録などに適しています。
matcher マッチ: ツール名
追加入力フィールド:
{
"session_id": "abc-123",
"cwd": "/path/to/project",
"hook_event_name": "PostToolUseFailure",
"tool_name": "Bash",
"tool_input": { "command": "npm test" },
"error": "Command exited with non-zero status code 1"
}
| フィールド | 型 | 説明 |
|---|
error | string | ツール実行のエラーメッセージ |
Stop
Agent がレスポンスを返し終えた後(実行待ちのツール呼び出しがない状態)に発火します。ブロックはできません。デスクトップ通知やログ記録、タスクのステータス報告などに適しています。
現在のバージョンでは Stop イベントはブロックに対応していません(exit 2 で Agent に作業を継続させることはできません)。この機能は次のバージョンで対応予定です。
matcher マッチ: マッチ対象のフィールドはなく、Agent の停止時に一律で発火します。
追加入力フィールド:
{
"session_id": "abc-123",
"cwd": "/path/to/project",
"hook_event_name": "Stop",
"stop_hook_active": true,
"last_assistant_message": "I have finished writing the sort function."
}
stdout JSON 出力フィールド(exit 0 の場合。次のバージョンで有効化予定):
{
"decision": "block",
"reason": "Tests failing. Fix them before completing."
}
| フィールド | 型 | 説明 |
|---|
decision | string | "block"(停止をブロックし、Agent に作業を継続させる) |
reason | string | ブロックの理由。メッセージとして会話に注入される |
実用例
危険コマンドの遮断
Agent がシェルコマンドを実行する前に、rm -rf や DROP TABLE などの危険な操作が含まれていないかをチェックします。
スクリプト ~/.qoder/hooks/block-dangerous.sh:
#!/bin/bash
input=$(cat)
command=$(echo "$input" | jq -r '.tool_input.command')
# Check for dangerous patterns
if echo "$command" | grep -qE 'rm\s+-rf|DROP\s+TABLE|mkfs|dd\s+if='; then
echo "Dangerous command blocked: $command" >&2
exit 2
fi
exit 0
設定: イベント PreToolUse、matcher Bash ,command ~/.qoder/hooks/block-dangerous.sh。
ファイル書き込み後の自動 Lint
Agent がファイルを書き込み・編集するたびに、自動で lint を実行します。
スクリプト ${project}/.qoder/hooks/auto-lint.sh:
#!/bin/bash
input=$(cat)
file_path=$(echo "$input" | jq -r '.tool_input.file_path')
# Only lint JS/TS files
case "$file_path" in
*.js|*.ts|*.jsx|*.tsx)
npx eslint "$file_path" --fix 2>/dev/null
;;
esac
exit 0
設定: イベント PostToolUse、matcher Write|Edit,command .qoder/hooks/auto-lint.sh。
ツール失敗時のログ記録
ツールの実行が失敗した際に、自動でログファイルに記録して問題の調査に役立てます。
スクリプト ~/.qoder/hooks/log-failure.sh:
#!/bin/bash
input=$(cat)
tool_name=$(echo "$input" | jq -r '.tool_name')
error=$(echo "$input" | jq -r '.error')
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] $tool_name failed: $error" >> ~/.qoder/hooks/failure.log
exit 0
設定: イベント PostToolUseFailure、matcher なし(すべてのツールにマッチ),command ~/.qoder/hooks/log-failure.sh。
Agent 完了時のデスクトップ通知
Agent がタスクを完了したらシステム通知を表示します。長時間かかるタスクに便利です。
スクリプト ~/.qoder/hooks/notify-done.sh(macOS):
#!/bin/bash
input=$(cat)
message=$(echo "$input" | jq -r '.last_assistant_message // "Task complete"' | head -c 100)
osascript -e "display notification \"$message\" with title \"Qoder Agent\""
exit 0
設定: イベント Stop、matcher なし,command ~/.qoder/hooks/notify-done.sh。
Prompt の内容チェック
ユーザーが Prompt を送信する際に、機密情報(パスワード、キーなど)が含まれていないかをチェックし、意図しない漏洩を防ぎます。
スクリプト ~/.qoder/hooks/check-prompt.sh:
#!/bin/bash
input=$(cat)
prompt=$(echo "$input" | jq -r '.prompt')
# Check for possible credential patterns
if echo "$prompt" | grep -qiE '(password|secret|api_key|token)\s*[:=]\s*\S+'; then
echo "Sensitive information detected in prompt. Please review and resubmit." >&2
exit 2
fi
exit 0
設定: イベント UserPromptSubmit、matcher なし,command ~/.qoder/hooks/check-prompt.sh。
完全な設定例
以下は 5 つのイベントすべてに Hook を設定した完全な例です。
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "~/.qoder/hooks/check-prompt.sh"
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "~/.qoder/hooks/block-dangerous.sh"
}
]
},
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": ".qoder/hooks/validate-file-path.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": ".qoder/hooks/auto-lint.sh"
}
]
}
],
"PostToolUseFailure": [
{
"hooks": [
{
"type": "command",
"command": "~/.qoder/hooks/log-failure.sh"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "~/.qoder/hooks/notify-done.sh"
}
]
}
]
}
}
注意事項
- タイムアウト: Hook スクリプトのデフォルトタイムアウトは 30 秒です。タイムアウトするとスクリプトは強制終了され、続行(許可)として扱われます。カスタムタイムアウトは次のバージョンで対応予定です。
- エラー処理: スクリプトが異常終了した場合(exit code が 0 でも 2 でもない場合)、エラーメッセージがユーザーに表示されますが、Agent の処理は中断されず続行されます。
- スクリプト権限: スクリプトに実行権限が付与されていることを確認してください(
chmod +x)。
- 設定のマージ: 複数レベルの設定ファイルに同一イベントの Hook がある場合、優先度の低い順に実行されます。いずれかの Hook がブロック(exit 2)を返した時点で、以降の Hook は実行されません。
- jq の依存: サンプルスクリプトでは JSON 解析に
jq を使用しています。システムに jq がインストールされていることを確認してください(macOS: brew install jq、Linux: apt install jq)。