Skip to main content

フックの構成

GitHub Copilot CLI(コマンドラインインターフェース) および Copilot コーディング エージェント で使用するフックの構成に関する情報を確認します。

このリファレンス記事では、入力形式と出力形式、スクリプトのベスト プラクティス、ログ記録、セキュリティ適用、外部統合の高度なパターンなど、使用可能なフックの種類と例について説明します。 フックの作成に関する一般的な情報については、 AUTOTITLE を参照してください。

フックの種類

セッション開始フック

新しいエージェント セッションの開始時または既存のセッションの再開時に実行されます。

          **入力 JSON:**
JSON
{
  "timestamp": 1704614400000,
  "cwd": "/path/to/project",
  "source": "new",
  "initialPrompt": "Create a new feature"
}
          **フィールド:**

* timestamp: Unix タイムスタンプ (ミリ秒) * cwd: 現在の作業ディレクトリ * source: "new" (新しいセッション)、 "resume" (再開されたセッション)、または "startup" * initialPrompt: ユーザーの最初のプロンプト (指定されている場合)

          **出力:** 無視 (戻り値は処理されません)

          **フックの例:**
JSON
{
  "type": "command",
  "bash": "./scripts/session-start.sh",
  "powershell": "./scripts/session-start.ps1",
  "cwd": "scripts",
  "timeoutSec": 30
}
          **サンプル スクリプト (Bash):**
Shell
#!/bin/bash
INPUT=$(cat)
SOURCE=$(echo "$INPUT" | jq -r '.source')
TIMESTAMP=$(echo "$INPUT" | jq -r '.timestamp')

echo "Session started from $SOURCE at $TIMESTAMP" >> session.log

セッション終了フック

エージェント セッションが完了または終了したときに実行されます。

          **入力 JSON:**
JSON
{
  "timestamp": 1704618000000,
  "cwd": "/path/to/project",
  "reason": "complete"
}
          **フィールド:**

* timestamp: Unix タイムスタンプ (ミリ秒) * cwd: 現在の作業ディレクトリ * reason: "complete""error""abort""timeout"、または "user_exit"

          **出力:** 無視されました

          **スクリプトの例:**
Shell
#!/bin/bash
INPUT=$(cat)
REASON=$(echo "$INPUT" | jq -r '.reason')

echo "Session ended: $REASON" >> session.log
# Cleanup temporary files
rm -rf /tmp/session-*

ユーザープロンプト送信のフック

ユーザーがエージェントにプロンプトを送信したときに実行されます。

          **入力 JSON:**
JSON
{
  "timestamp": 1704614500000,
  "cwd": "/path/to/project",
  "prompt": "Fix the authentication bug"
}
          **フィールド:**

* timestamp: Unix タイムスタンプ (ミリ秒) * cwd: 現在の作業ディレクトリ * prompt: ユーザーが送信した正確なテキスト

          **出力:** 無視されました (顧客フックでは現在プロンプトの変更はサポートされていません)

          **スクリプトの例:**
Shell
#!/bin/bash
INPUT=$(cat)
PROMPT=$(echo "$INPUT" | jq -r '.prompt')
TIMESTAMP=$(echo "$INPUT" | jq -r '.timestamp')

# Log to a structured file
echo "$(date -d @$((TIMESTAMP/1000))): $PROMPT" >> prompts.log

ツール使用前のフック

エージェントが任意のツール ( basheditviewなど) を使用する前に実行されます。 これは、 ツールの実行を承認または拒否できるため、最も強力なフックです。

          **入力 JSON:**
JSON
{
  "timestamp": 1704614600000,
  "cwd": "/path/to/project",
  "toolName": "bash",
  "toolArgs": "{\"command\":\"rm -rf dist\",\"description\":\"Clean build directory\"}"
}
          **フィールド:**

* timestamp: Unix タイムスタンプ (ミリ秒) * cwd: 現在の作業ディレクトリ * toolName: 呼び出されるツールの名前 ("bash"、"edit"、"view"、"create" など) * toolArgs: ツールの引数を含む JSON 文字列

          **出力 JSON (省略可能):**
JSON
{
  "permissionDecision": "deny",
  "permissionDecisionReason": "Destructive operations require approval"
}
          **出力フィールド:**

* permissionDecision: "allow""deny"、または "ask" (現在処理されている "deny" のみ) * permissionDecisionReason: 決定に関する人間が判読できる説明

          **危険なコマンドをブロックするフックの例:**
Shell
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.toolName')
TOOL_ARGS=$(echo "$INPUT" | jq -r '.toolArgs')

# Log the tool use
echo "$(date): Tool=$TOOL_NAME Args=$TOOL_ARGS" >> tool-usage.log

# Check for dangerous patterns
if echo "$TOOL_ARGS" | grep -qE "rm -rf /|format|DROP TABLE"; then
  echo '{"permissionDecision":"deny","permissionDecisionReason":"Dangerous command detected"}'
  exit 0
fi

# Allow by default (or omit output to allow)
echo '{"permissionDecision":"allow"}'
          **ファイルのアクセス許可を適用するフックの例:**
Shell
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.toolName')

# Only allow editing specific directories
if [ "$TOOL_NAME" = "edit" ]; then
  PATH_ARG=$(echo "$INPUT" | jq -r '.toolArgs' | jq -r '.path')
  
  if [[ ! "$PATH_ARG" =~ ^(src/|test/) ]]; then
    echo '{"permissionDecision":"deny","permissionDecisionReason":"Can only edit files in src/ or test/ directories"}'
    exit 0
  fi
fi

# Allow all other tools

ツール利用後のフック

ツールの実行が完了した後に実行されます (成功したか失敗したか)。

          **入力 JSON の例:**
JSON
{
  "timestamp": 1704614700000,
  "cwd": "/path/to/project",
  "toolName": "bash",
  "toolArgs": "{\"command\":\"npm test\"}",
  "toolResult": {
    "resultType": "success",
    "textResultForLlm": "All tests passed (15/15)"
  }
}
          **フィールド:**

* timestamp: Unix タイムスタンプ (ミリ秒) * cwd: 現在の作業ディレクトリ * toolName: 実行されたツールの名前 * toolArgs: ツールの引数を含む JSON 文字列 * toolResult: 次を含む Result オブジェクト: * resultType: "success""failure"、または "denied" * textResultForLlm: エージェントに表示される結果テキスト

          **出力:** 無視 (結果の変更は現在サポートされていません)

          **ツールの実行統計を CSV ファイルに記録するスクリプトの例:**

このスクリプトは、ツールの実行統計を CSV ファイルに記録し、ツールが失敗したときに電子メール アラートを送信します。

Shell
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.toolName')
RESULT_TYPE=$(echo "$INPUT" | jq -r '.toolResult.resultType')

# Track statistics
echo "$(date),${TOOL_NAME},${RESULT_TYPE}" >> tool-stats.csv

# Alert on failures
if [ "$RESULT_TYPE" = "failure" ]; then
  RESULT_TEXT=$(echo "$INPUT" | jq -r '.toolResult.textResultForLlm')
  echo "FAILURE: $TOOL_NAME - $RESULT_TEXT" | mail -s "Agent Tool Failed" admin@example.com
fi

フックのエラーが発生しました

エージェントの実行中にエラーが発生したときに実行されます。

          **入力 JSON の例:**
JSON
{
  "timestamp": 1704614800000,
  "cwd": "/path/to/project",
  "error": {
    "message": "Network timeout",
    "name": "TimeoutError",
    "stack": "TimeoutError: Network timeout\n    at ..."
  }
}
          **フィールド:**

* timestamp: Unix タイムスタンプ (ミリ秒) * cwd: 現在の作業ディレクトリ * error: 次を含む Error オブジェクト: * message: エラー メッセージ * name: エラーの種類/名前 * stack: スタック トレース (使用可能な場合)

          **出力:** 無視 (エラー処理の変更は現在サポートされていません)

          **エラーの詳細をログ ファイルに抽出するスクリプトの例:**
Shell
#!/bin/bash
INPUT=$(cat)
ERROR_MSG=$(echo "$INPUT" | jq -r '.error.message')
ERROR_NAME=$(echo "$INPUT" | jq -r '.error.name')

echo "$(date): [$ERROR_NAME] $ERROR_MSG" >> errors.log

スクリプトのベスト プラクティス

入力の読み取り

このサンプル スクリプトは、stdin から変数に JSON 入力を読み取り、 jq を使用して timestamp フィールドと cwd フィールドを抽出します。

          **Bash:**
Shell
#!/bin/bash
# Read JSON from stdin
INPUT=$(cat)

# Parse with jq
TIMESTAMP=$(echo "$INPUT" | jq -r '.timestamp')
CWD=$(echo "$INPUT" | jq -r '.cwd')
          **PowerShell**:
PowerShell
# Read JSON from stdin
$input = [Console]::In.ReadToEnd() | ConvertFrom-Json

# Access properties
$timestamp = $input.timestamp
$cwd = $input.cwd

JSON の出力

このサンプル スクリプトは、フック スクリプトから有効な JSON を出力する方法を示しています。 Bash で jq -c を使用して、コンパクトな単一行出力を行うか、PowerShell で ConvertTo-Json -Compress します。

          **Bash:**
Shell
#!/bin/bash
# Use jq to compact the JSON output to a single line
echo '{"permissionDecision":"deny","permissionDecisionReason":"Security policy violation"}' | jq -c

# Or construct with variables
REASON="Too dangerous"
jq -n --arg reason "$REASON" '{permissionDecision: "deny", permissionDecisionReason: $reason}'
          **PowerShell**:
PowerShell
# Use ConvertTo-Json to compact the JSON output to a single line
$output = @{
    permissionDecision = "deny"
    permissionDecisionReason = "Security policy violation"
}
$output | ConvertTo-Json -Compress

エラー処理

このスクリプトの例では、フック スクリプトでエラーを処理する方法を示します。

          **Bash:**
Shell
#!/bin/bash
set -e  # Exit on error

INPUT=$(cat)
# ... process input ...

# Exit with 0 for success
exit 0
          **PowerShell**:
PowerShell
$ErrorActionPreference = "Stop"

try {
    $input = [Console]::In.ReadToEnd() | ConvertFrom-Json
    # ... process input ...
    exit 0
} catch {
    Write-Error $_.Exception.Message
    exit 1
}

タイムアウトの処理

フックの既定のタイムアウトは 30 秒です。 操作を長くする場合は、 timeoutSecを増やします。

JSON
{
  "type": "command",
  "bash": "./scripts/slow-validation.sh",
  "timeoutSec": 120
}

高度なパターン

同じ型の複数のフック

同じイベントに対して複数のフックを定義できます。 これらは次の順序で実行されます。

JSON
{
  "version": 1,
  "hooks": {
    "preToolUse": [
      {
        "type": "command",
        "bash": "./scripts/security-check.sh",
        "comment": "Security validation - runs first"
      },
      {
        "type": "command", 
        "bash": "./scripts/audit-log.sh",
        "comment": "Audit logging - runs second"
      },
      {
        "type": "command",
        "bash": "./scripts/metrics.sh",
        "comment": "Metrics collection - runs third"
      }
    ]
  }
}

スクリプトの条件付きロジック

          **例: 特定のツールのみをブロックする**
Shell
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.toolName')

# Only validate bash commands
if [ "$TOOL_NAME" != "bash" ]; then
  exit 0  # Allow all non-bash tools
fi

# Check bash command for dangerous patterns
COMMAND=$(echo "$INPUT" | jq -r '.toolArgs' | jq -r '.command')
if echo "$COMMAND" | grep -qE "rm -rf|sudo|mkfs"; then
  echo '{"permissionDecision":"deny","permissionDecisionReason":"Dangerous system command"}'
fi

構造化ログ

          **例: JSON Lines 形式**
Shell
#!/bin/bash
INPUT=$(cat)
TIMESTAMP=$(echo "$INPUT" | jq -r '.timestamp')
TOOL_NAME=$(echo "$INPUT" | jq -r '.toolName')
RESULT_TYPE=$(echo "$INPUT" | jq -r '.toolResult.resultType')

# Output structured log entry
jq -n \
  --arg ts "$TIMESTAMP" \
  --arg tool "$TOOL_NAME" \
  --arg result "$RESULT_TYPE" \
  '{timestamp: $ts, tool: $tool, result: $result}' >> logs/audit.jsonl

外部システムとの統合

          **例: Slack にアラートを送信する**
Shell
#!/bin/bash
INPUT=$(cat)
ERROR_MSG=$(echo "$INPUT" | jq -r '.error.message')

WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"

curl -X POST "$WEBHOOK_URL" \
  -H 'Content-Type: application/json' \
  -d "{\"text\":\"Agent Error: $ERROR_MSG\"}"

利用事例の例

コンプライアンス監査証跡

ログ スクリプトを使用して、コンプライアンス要件のすべてのエージェント アクションをログに記録します。

JSON
{
  "version": 1,
  "hooks": {
    "sessionStart": [{"type": "command", "bash": "./audit/log-session-start.sh"}],
    "userPromptSubmitted": [{"type": "command", "bash": "./audit/log-prompt.sh"}],
    "preToolUse": [{"type": "command", "bash": "./audit/log-tool-use.sh"}],
    "postToolUse": [{"type": "command", "bash": "./audit/log-tool-result.sh"}],
    "sessionEnd": [{"type": "command", "bash": "./audit/log-session-end.sh"}]
  }
}

コストの追跡

コストの割り当てに関するツールの使用状況を追跡します。

Shell
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.toolName')
TIMESTAMP=$(echo "$INPUT" | jq -r '.timestamp')
USER=${USER:-unknown}

echo "$TIMESTAMP,$USER,$TOOL_NAME" >> /var/log/copilot/usage.csv

コード品質の強制実施

コード標準に違反するコミットを防ぐ:

Shell
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.toolName')

if [ "$TOOL_NAME" = "edit" ] || [ "$TOOL_NAME" = "create" ]; then
  # Run linter before allowing edits
  npm run lint-staged
  if [ $? -ne 0 ]; then
    echo '{"permissionDecision":"deny","permissionDecisionReason":"Code does not pass linting"}'
  fi
fi

通知システム

重要なイベントに関する通知を送信します。

Shell
#!/bin/bash
INPUT=$(cat)
PROMPT=$(echo "$INPUT" | jq -r '.prompt')

# Notify on production-related prompts
if echo "$PROMPT" | grep -iq "production"; then
  echo "ALERT: Production-related prompt: $PROMPT" | mail -s "Agent Alert" team@example.com
fi