Skip to main content

후크 구성

GitHub Copilot CLI와 Copilot 코딩 도우미와 함께 사용할 후크 구성 방법에 대한 정보를 찾습니다.

이 참조 문서에서는 입력 및 출력 형식, 스크립트 모범 사례 및 로깅, 보안 적용 및 외부 통합에 대한 고급 패턴을 포함하여 예제와 함께 사용 가능한 후크 형식에 대해 설명합니다. 후크를 만드는 방법에 대한 일반적인 내용은 GitHub Copilot 에이전트와 후크 활용을 참조하세요. CLI에 대한 후크를 만드는 방법에 대한 자습서는 예측 가능한 정책 준수를 위해 Copilot CLI와 연결고리 사용을 참조하세요.

후크 형식

세션 시작 후크

새 에이전트 세션이 시작되거나 기존 세션을 다시 시작할 때 실행됩니다.

          **입력 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

사전 도구 사용 후크

에이전트가 모든 도구(예: bash, edit``view)를 사용하기 전에 실행됩니다. 도구 실행을 승인하거나 거부할 수 있는 가장 강력한 후크입니다.

          **입력 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: 다음을 포함하는 결과 개체: * 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" [email protected]
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: 다음을 포함하는 오류 개체입니다. * 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를 사용하여 timestampcwd 필드를 추출합니다.

          **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 줄 형식**
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" [email protected]
fi