Untuk panduan quickstart dengan contoh, lihat Memulai dengan Claude Code hooks.

Konfigurasi

Claude Code hooks dikonfigurasi dalam file pengaturan Anda:
  • ~/.claude/settings.json - Pengaturan pengguna
  • .claude/settings.json - Pengaturan proyek
  • .claude/settings.local.json - Pengaturan proyek lokal (tidak di-commit)
  • Pengaturan kebijakan yang dikelola Enterprise

Struktur

Hooks diorganisir berdasarkan matchers, di mana setiap matcher dapat memiliki beberapa hooks:
{
  "hooks": {
    "EventName": [
      {
        "matcher": "ToolPattern",
        "hooks": [
          {
            "type": "command",
            "command": "your-command-here"
          }
        ]
      }
    ]
  }
}
  • matcher: Pola untuk mencocokkan nama alat, peka huruf besar-kecil (hanya berlaku untuk PreToolUse dan PostToolUse)
    • String sederhana cocok persis: Write hanya cocok dengan alat Write
    • Mendukung regex: Edit|Write atau Notebook.*
    • Gunakan * untuk mencocokkan semua alat. Anda juga dapat menggunakan string kosong ("") atau membiarkan matcher kosong.
  • hooks: Array perintah yang akan dijalankan ketika pola cocok
    • type: Saat ini hanya "command" yang didukung
    • command: Perintah bash yang akan dijalankan (dapat menggunakan variabel lingkungan $CLAUDE_PROJECT_DIR)
    • timeout: (Opsional) Berapa lama perintah harus berjalan, dalam detik, sebelum membatalkan perintah tertentu itu.
Untuk acara seperti UserPromptSubmit, Notification, Stop, dan SubagentStop yang tidak menggunakan matchers, Anda dapat menghilangkan field matcher:
{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/prompt-validator.py"
          }
        ]
      }
    ]
  }
}

Skrip Hook Khusus Proyek

Anda dapat menggunakan variabel lingkungan CLAUDE_PROJECT_DIR (hanya tersedia ketika Claude Code menjalankan perintah hook) untuk mereferensikan skrip yang disimpan di proyek Anda, memastikan mereka bekerja terlepas dari direktori saat ini Claude:
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/check-style.sh"
          }
        ]
      }
    ]
  }
}

Hooks plugin

Plugin dapat menyediakan hooks yang terintegrasi dengan mulus dengan hooks pengguna dan proyek Anda. Hooks plugin secara otomatis digabungkan dengan konfigurasi Anda ketika plugin diaktifkan. Cara kerja hooks plugin:
  • Hooks plugin didefinisikan dalam file hooks/hooks.json plugin atau dalam file yang diberikan oleh jalur kustom ke field hooks.
  • Ketika plugin diaktifkan, hooks-nya digabungkan dengan hooks pengguna dan proyek
  • Beberapa hooks dari sumber berbeda dapat merespons acara yang sama
  • Hooks plugin menggunakan variabel lingkungan ${CLAUDE_PLUGIN_ROOT} untuk mereferensikan file plugin
Contoh konfigurasi hook plugin:
{
  "description": "Automatic code formatting",
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PLUGIN_ROOT}/scripts/format.sh",
            "timeout": 30
          }
        ]
      }
    ]
  }
}
Hooks plugin menggunakan format yang sama dengan hooks reguler dengan field description opsional untuk menjelaskan tujuan hook.
Hooks plugin berjalan bersama hooks kustom Anda. Jika beberapa hooks cocok dengan acara, semuanya dijalankan secara paralel.
Variabel lingkungan untuk plugin:
  • ${CLAUDE_PLUGIN_ROOT}: Jalur absolut ke direktori plugin
  • ${CLAUDE_PROJECT_DIR}: Direktori root proyek (sama seperti untuk hooks proyek)
  • Semua variabel lingkungan standar tersedia
Lihat referensi komponen plugin untuk detail tentang membuat hooks plugin.

Hook Events

PreToolUse

Berjalan setelah Claude membuat parameter alat dan sebelum memproses panggilan alat. Matchers umum:
  • Task - Tugas subagent (lihat dokumentasi subagents)
  • Bash - Perintah shell
  • Glob - Pencocokan pola file
  • Grep - Pencarian konten
  • Read - Pembacaan file
  • Edit - Pengeditan file
  • Write - Penulisan file
  • WebFetch, WebSearch - Operasi web

PostToolUse

Berjalan segera setelah alat selesai dengan sukses. Mengenali nilai matcher yang sama seperti PreToolUse.

Notification

Berjalan ketika Claude Code mengirim notifikasi. Notifikasi dikirim ketika:
  1. Claude membutuhkan izin Anda untuk menggunakan alat. Contoh: “Claude membutuhkan izin Anda untuk menggunakan Bash”
  2. Input prompt telah idle selama minimal 60 detik. “Claude menunggu input Anda”

UserPromptSubmit

Berjalan ketika pengguna mengirimkan prompt, sebelum Claude memprosesnya. Ini memungkinkan Anda untuk menambahkan konteks tambahan berdasarkan prompt/percakapan, memvalidasi prompt, atau memblokir jenis prompt tertentu.

Stop

Berjalan ketika agen Claude Code utama selesai merespons. Tidak berjalan jika penghentian terjadi karena gangguan pengguna.

SubagentStop

Berjalan ketika subagent Claude Code (panggilan alat Task) selesai merespons.

PreCompact

Berjalan sebelum Claude Code akan menjalankan operasi compact. Matchers:
  • manual - Dipanggil dari /compact
  • auto - Dipanggil dari auto-compact (karena jendela konteks penuh)

SessionStart

Berjalan ketika Claude Code memulai sesi baru atau melanjutkan sesi yang ada (yang saat ini memulai sesi baru di bawah tenda). Berguna untuk memuat konteks pengembangan seperti masalah yang ada atau perubahan terbaru pada codebase Anda, menginstal dependensi, atau menyiapkan variabel lingkungan. Matchers:
  • startup - Dipanggil dari startup
  • resume - Dipanggil dari --resume, --continue, atau /resume
  • clear - Dipanggil dari /clear
  • compact - Dipanggil dari compact otomatis atau manual.

Mempertahankan variabel lingkungan

Hook SessionStart memiliki akses ke variabel lingkungan CLAUDE_ENV_FILE, yang menyediakan jalur file di mana Anda dapat mempertahankan variabel lingkungan untuk perintah bash berikutnya. Contoh: Menetapkan variabel lingkungan individual
#!/bin/bash

if [ -n "$CLAUDE_ENV_FILE" ]; then
  echo 'export NODE_ENV=production' >> "$CLAUDE_ENV_FILE"
  echo 'export API_KEY=your-api-key' >> "$CLAUDE_ENV_FILE"
  echo 'export PATH="$PATH:./node_modules/.bin"' >> "$CLAUDE_ENV_FILE"
fi

exit 0
Contoh: Mempertahankan semua perubahan lingkungan dari hook Ketika setup Anda memodifikasi lingkungan (misalnya, nvm use), tangkap dan pertahankan semua perubahan dengan membedakan lingkungan:
#!/bin/bash

ENV_BEFORE=$(export -p | sort)

# Run your setup commands that modify the environment
source ~/.nvm/nvm.sh
nvm use 20

if [ -n "$CLAUDE_ENV_FILE" ]; then
  ENV_AFTER=$(export -p | sort)
  comm -13 <(echo "$ENV_BEFORE") <(echo "$ENV_AFTER") >> "$CLAUDE_ENV_FILE"
fi

exit 0
Variabel apa pun yang ditulis ke file ini akan tersedia di semua perintah bash berikutnya yang dijalankan Claude Code selama sesi.
CLAUDE_ENV_FILE hanya tersedia untuk hook SessionStart. Jenis hook lainnya tidak memiliki akses ke variabel ini.

SessionEnd

Berjalan ketika sesi Claude Code berakhir. Berguna untuk tugas pembersihan, pencatatan statistik sesi, atau penyimpanan status sesi. Field reason dalam input hook akan menjadi salah satu dari:
  • clear - Sesi dihapus dengan perintah /clear
  • logout - Pengguna logout
  • prompt_input_exit - Pengguna keluar saat input prompt terlihat
  • other - Alasan keluar lainnya

Hook Input

Hooks menerima data JSON melalui stdin yang berisi informasi sesi dan data spesifik acara:
{
  // Common fields
  session_id: string
  transcript_path: string  // Path to conversation JSON
  cwd: string              // The current working directory when the hook is invoked
  permission_mode: string  // Current permission mode: "default", "plan", "acceptEdits", or "bypassPermissions"

  // Event-specific fields
  hook_event_name: string
  ...
}

PreToolUse Input

Skema tepat untuk tool_input tergantung pada alatnya.
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "PreToolUse",
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/path/to/file.txt",
    "content": "file content"
  }
}

PostToolUse Input

Skema tepat untuk tool_input dan tool_response tergantung pada alatnya.
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "PostToolUse",
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/path/to/file.txt",
    "content": "file content"
  },
  "tool_response": {
    "filePath": "/path/to/file.txt",
    "success": true
  }
}

Notification Input

{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "Notification",
  "message": "Task completed successfully"
}

UserPromptSubmit Input

{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "UserPromptSubmit",
  "prompt": "Write a function to calculate the factorial of a number"
}

Stop dan SubagentStop Input

stop_hook_active adalah true ketika Claude Code sudah melanjutkan sebagai hasil dari hook stop. Periksa nilai ini atau proses transkrip untuk mencegah Claude Code berjalan tanpa batas.
{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "permission_mode": "default",
  "hook_event_name": "Stop",
  "stop_hook_active": true
}

PreCompact Input

Untuk manual, custom_instructions berasal dari apa yang dilewatkan pengguna ke /compact. Untuk auto, custom_instructions kosong.
{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "permission_mode": "default",
  "hook_event_name": "PreCompact",
  "trigger": "manual",
  "custom_instructions": ""
}

SessionStart Input

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "permission_mode": "default",
  "hook_event_name": "SessionStart",
  "source": "startup"
}

SessionEnd Input

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "SessionEnd",
  "reason": "exit"
}

Hook Output

Ada dua cara untuk hooks mengembalikan output kembali ke Claude Code. Output mengkomunikasikan apakah akan memblokir dan umpan balik apa pun yang harus ditampilkan kepada Claude dan pengguna.

Sederhana: Exit Code

Hooks mengkomunikasikan status melalui exit codes, stdout, dan stderr:
  • Exit code 0: Sukses. stdout ditampilkan kepada pengguna dalam mode transkrip (CTRL-R), kecuali untuk UserPromptSubmit dan SessionStart, di mana stdout ditambahkan ke konteks.
  • Exit code 2: Kesalahan pemblokiran. stderr diumpankan kembali ke Claude untuk diproses secara otomatis. Lihat perilaku per-hook-event di bawah.
  • Exit codes lainnya: Kesalahan non-pemblokiran. stderr ditampilkan kepada pengguna dan eksekusi berlanjut.
Pengingat: Claude Code tidak melihat stdout jika exit code adalah 0, kecuali untuk hook UserPromptSubmit di mana stdout disuntikkan sebagai konteks.

Perilaku Exit Code 2

Hook EventPerilaku
PreToolUseMemblokir panggilan alat, menampilkan stderr ke Claude
PostToolUseMenampilkan stderr ke Claude (alat sudah berjalan)
NotificationN/A, menampilkan stderr ke pengguna saja
UserPromptSubmitMemblokir pemrosesan prompt, menghapus prompt, menampilkan stderr ke pengguna saja
StopMemblokir penghentian, menampilkan stderr ke Claude
SubagentStopMemblokir penghentian, menampilkan stderr ke subagent Claude
PreCompactN/A, menampilkan stderr ke pengguna saja
SessionStartN/A, menampilkan stderr ke pengguna saja
SessionEndN/A, menampilkan stderr ke pengguna saja

Lanjutan: JSON Output

Hooks dapat mengembalikan JSON terstruktur dalam stdout untuk kontrol yang lebih canggih:

Field JSON Umum

Semua jenis hook dapat menyertakan field opsional ini:
{
  "continue": true, // Whether Claude should continue after hook execution (default: true)
  "stopReason": "string", // Message shown when continue is false

  "suppressOutput": true, // Hide stdout from transcript mode (default: false)
  "systemMessage": "string" // Optional warning message shown to the user
}
Jika continue adalah false, Claude berhenti memproses setelah hooks berjalan.
  • Untuk PreToolUse, ini berbeda dari "permissionDecision": "deny", yang hanya memblokir panggilan alat tertentu dan memberikan umpan balik otomatis ke Claude.
  • Untuk PostToolUse, ini berbeda dari "decision": "block", yang memberikan umpan balik otomatis ke Claude.
  • Untuk UserPromptSubmit, ini mencegah prompt dari diproses.
  • Untuk Stop dan SubagentStop, ini mengambil alih dari apa pun output "decision": "block".
  • Dalam semua kasus, "continue" = false mengambil alih dari apa pun output "decision": "block".
stopReason menemani continue dengan alasan yang ditampilkan kepada pengguna, tidak ditampilkan ke Claude.

Kontrol Keputusan PreToolUse

Hook PreToolUse dapat mengontrol apakah panggilan alat dilanjutkan.
  • "allow" melewati sistem izin. permissionDecisionReason ditampilkan kepada pengguna tetapi tidak ke Claude.
  • "deny" mencegah panggilan alat dari dijalankan. permissionDecisionReason adalah ditampilkan ke Claude.
  • "ask" meminta pengguna untuk mengkonfirmasi panggilan alat di UI. permissionDecisionReason ditampilkan kepada pengguna tetapi tidak ke Claude.
Selain itu, hooks dapat memodifikasi input alat sebelum eksekusi menggunakan updatedInput:
  • updatedInput memungkinkan Anda untuk memodifikasi parameter input alat sebelum alat dijalankan. Ini adalah objek Record<string, unknown> yang berisi field yang ingin Anda ubah atau tambahkan.
  • Ini paling berguna dengan "permissionDecision": "allow" untuk memodifikasi dan menyetujui panggilan alat.
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow"
    "permissionDecisionReason": "My reason here",
    "updatedInput": {
      "field_to_modify": "new value"
    }
  }
}
Field decision dan reason sudah usang untuk hook PreToolUse. Gunakan hookSpecificOutput.permissionDecision dan hookSpecificOutput.permissionDecisionReason sebagai gantinya. Field usang "approve" dan "block" memetakan ke "allow" dan "deny" masing-masing.

Kontrol Keputusan PostToolUse

Hook PostToolUse dapat memberikan umpan balik ke Claude setelah eksekusi alat.
  • "block" secara otomatis meminta Claude dengan reason.
  • undefined tidak melakukan apa pun. reason diabaikan.
  • "hookSpecificOutput.additionalContext" menambahkan konteks untuk Claude pertimbangkan.
{
  "decision": "block" | undefined,
  "reason": "Explanation for decision",
  "hookSpecificOutput": {
    "hookEventName": "PostToolUse",
    "additionalContext": "Additional information for Claude"
  }
}

Kontrol Keputusan UserPromptSubmit

Hook UserPromptSubmit dapat mengontrol apakah prompt pengguna diproses.
  • "block" mencegah prompt dari diproses. Prompt yang dikirimkan dihapus dari konteks. "reason" ditampilkan kepada pengguna tetapi tidak ditambahkan ke konteks.
  • undefined memungkinkan prompt untuk melanjutkan secara normal. "reason" diabaikan.
  • "hookSpecificOutput.additionalContext" menambahkan string ke konteks jika tidak diblokir.
{
  "decision": "block" | undefined,
  "reason": "Explanation for decision",
  "hookSpecificOutput": {
    "hookEventName": "UserPromptSubmit",
    "additionalContext": "My additional context here"
  }
}

Kontrol Keputusan Stop/SubagentStop

Hook Stop dan SubagentStop dapat mengontrol apakah Claude harus melanjutkan.
  • "block" mencegah Claude dari berhenti. Anda harus mengisi reason untuk Claude tahu cara melanjutkan.
  • undefined memungkinkan Claude untuk berhenti. reason diabaikan.
{
  "decision": "block" | undefined,
  "reason": "Must be provided when Claude is blocked from stopping"
}

Kontrol Keputusan SessionStart

Hook SessionStart memungkinkan Anda untuk memuat konteks di awal sesi.
  • "hookSpecificOutput.additionalContext" menambahkan string ke konteks.
  • Nilai additionalContext dari beberapa hooks digabungkan.
{
  "hookSpecificOutput": {
    "hookEventName": "SessionStart",
    "additionalContext": "My additional context here"
  }
}

Kontrol Keputusan SessionEnd

Hook SessionEnd berjalan ketika sesi berakhir. Mereka tidak dapat memblokir penghentian sesi tetapi dapat melakukan tugas pembersihan.

Contoh Exit Code: Validasi Perintah Bash

#!/usr/bin/env python3
import json
import re
import sys

# Define validation rules as a list of (regex pattern, message) tuples
VALIDATION_RULES = [
    (
        r"\bgrep\b(?!.*\|)",
        "Use 'rg' (ripgrep) instead of 'grep' for better performance and features",
    ),
    (
        r"\bfind\s+\S+\s+-name\b",
        "Use 'rg --files | rg pattern' or 'rg --files -g pattern' instead of 'find -name' for better performance",
    ),
]


def validate_command(command: str) -> list[str]:
    issues = []
    for pattern, message in VALIDATION_RULES:
        if re.search(pattern, command):
            issues.append(message)
    return issues


try:
    input_data = json.load(sys.stdin)
except json.JSONDecodeError as e:
    print(f"Error: Invalid JSON input: {e}", file=sys.stderr)
    sys.exit(1)

tool_name = input_data.get("tool_name", "")
tool_input = input_data.get("tool_input", {})
command = tool_input.get("command", "")

if tool_name != "Bash" or not command:
    sys.exit(1)

# Validate the command
issues = validate_command(command)

if issues:
    for message in issues:
        print(f"• {message}", file=sys.stderr)
    # Exit code 2 blocks tool call and shows stderr to Claude
    sys.exit(2)

Contoh JSON Output: UserPromptSubmit untuk Menambahkan Konteks dan Validasi

Untuk hook UserPromptSubmit, Anda dapat menyuntikkan konteks menggunakan salah satu metode:
  • Exit code 0 dengan stdout: Claude melihat konteks (kasus khusus untuk UserPromptSubmit)
  • JSON output: Memberikan kontrol yang lebih besar atas perilaku
#!/usr/bin/env python3
import json
import sys
import re
import datetime

# Load input from stdin
try:
    input_data = json.load(sys.stdin)
except json.JSONDecodeError as e:
    print(f"Error: Invalid JSON input: {e}", file=sys.stderr)
    sys.exit(1)

prompt = input_data.get("prompt", "")

# Check for sensitive patterns
sensitive_patterns = [
    (r"(?i)\b(password|secret|key|token)\s*[:=]", "Prompt contains potential secrets"),
]

for pattern, message in sensitive_patterns:
    if re.search(pattern, prompt):
        # Use JSON output to block with a specific reason
        output = {
            "decision": "block",
            "reason": f"Security policy violation: {message}. Please rephrase your request without sensitive information."
        }
        print(json.dumps(output))
        sys.exit(0)

# Add current time to context
context = f"Current time: {datetime.datetime.now()}"
print(context)

"""
The following is also equivalent:
print(json.dumps({
  "hookSpecificOutput": {
    "hookEventName": "UserPromptSubmit",
    "additionalContext": context,
  },
}))
"""

# Allow the prompt to proceed with the additional context
sys.exit(0)

Contoh JSON Output: PreToolUse dengan Persetujuan

#!/usr/bin/env python3
import json
import sys

# Load input from stdin
try:
    input_data = json.load(sys.stdin)
except json.JSONDecodeError as e:
    print(f"Error: Invalid JSON input: {e}", file=sys.stderr)
    sys.exit(1)

tool_name = input_data.get("tool_name", "")
tool_input = input_data.get("tool_input", {})

# Example: Auto-approve file reads for documentation files
if tool_name == "Read":
    file_path = tool_input.get("file_path", "")
    if file_path.endswith((".md", ".mdx", ".txt", ".json")):
        # Use JSON output to auto-approve the tool call
        output = {
            "decision": "approve",
            "reason": "Documentation file auto-approved",
            "suppressOutput": True  # Don't show in transcript mode
        }
        print(json.dumps(output))
        sys.exit(0)

# For other cases, let the normal permission flow proceed
sys.exit(0)

Bekerja dengan Alat MCP

Claude Code hooks bekerja dengan mulus dengan Model Context Protocol (MCP) tools. Ketika server MCP menyediakan alat, mereka muncul dengan pola penamaan khusus yang dapat Anda cocokkan di hooks Anda.

Penamaan Alat MCP

Alat MCP mengikuti pola mcp__<server>__<tool>, misalnya:
  • mcp__memory__create_entities - Alat create entities server Memory
  • mcp__filesystem__read_file - Alat read file server Filesystem
  • mcp__github__search_repositories - Alat search server GitHub

Mengonfigurasi Hooks untuk Alat MCP

Anda dapat menargetkan alat MCP tertentu atau seluruh server MCP:
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "mcp__memory__.*",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Memory operation initiated' >> ~/mcp-operations.log"
          }
        ]
      },
      {
        "matcher": "mcp__.*__write.*",
        "hooks": [
          {
            "type": "command",
            "command": "/home/user/scripts/validate-mcp-write.py"
          }
        ]
      }
    ]
  }
}

Contoh

Untuk contoh praktis termasuk pemformatan kode, notifikasi, dan perlindungan file, lihat Lebih Banyak Contoh dalam panduan memulai.

Pertimbangan Keamanan

Penafian

GUNAKAN DENGAN RISIKO ANDA SENDIRI: Claude Code hooks menjalankan perintah shell arbitrer pada sistem Anda secara otomatis. Dengan menggunakan hooks, Anda mengakui bahwa:
  • Anda sepenuhnya bertanggung jawab atas perintah yang Anda konfigurasi
  • Hooks dapat memodifikasi, menghapus, atau mengakses file apa pun yang dapat diakses akun pengguna Anda
  • Hooks yang berbahaya atau ditulis dengan buruk dapat menyebabkan kehilangan data atau kerusakan sistem
  • Anthropic tidak memberikan garansi dan tidak mengasumsikan tanggung jawab atas kerusakan apa pun yang dihasilkan dari penggunaan hooks
  • Anda harus menguji hooks secara menyeluruh di lingkungan yang aman sebelum penggunaan produksi
Selalu tinjau dan pahami perintah hook apa pun sebelum menambahkannya ke konfigurasi Anda.

Praktik Terbaik Keamanan

Berikut adalah beberapa praktik kunci untuk menulis hooks yang lebih aman:
  1. Validasi dan sanitasi input - Jangan pernah mempercayai data input secara membabi buta
  2. Selalu kutip variabel shell - Gunakan "$VAR" bukan $VAR
  3. Blokir path traversal - Periksa .. dalam jalur file
  4. Gunakan jalur absolut - Tentukan jalur lengkap untuk skrip (gunakan “$CLAUDE_PROJECT_DIR” untuk jalur proyek)
  5. Lewati file sensitif - Hindari .env, .git/, kunci, dll.

Keamanan Konfigurasi

Pengeditan langsung hooks dalam file pengaturan tidak langsung berlaku. Claude Code:
  1. Menangkap snapshot hooks saat startup
  2. Menggunakan snapshot ini sepanjang sesi
  3. Memperingatkan jika hooks dimodifikasi secara eksternal
  4. Memerlukan tinjauan dalam menu /hooks agar perubahan diterapkan
Ini mencegah modifikasi hook berbahaya dari mempengaruhi sesi saat ini Anda.

Detail Eksekusi Hook

  • Timeout: Batas eksekusi 60 detik secara default, dapat dikonfigurasi per perintah.
    • Timeout untuk perintah individual tidak mempengaruhi perintah lainnya.
  • Paralelisasi: Semua hooks yang cocok berjalan secara paralel
  • Deduplikasi: Perintah hook identik yang sama secara otomatis dihilangkan duplikatnya
  • Lingkungan: Berjalan di direktori saat ini dengan lingkungan Claude Code
    • Variabel lingkungan CLAUDE_PROJECT_DIR tersedia dan berisi jalur absolut ke direktori root proyek (di mana Claude Code dimulai)
    • Variabel lingkungan CLAUDE_CODE_REMOTE menunjukkan apakah hook berjalan di lingkungan jarak jauh (web) ("true") atau lingkungan CLI lokal (tidak diatur atau kosong). Gunakan ini untuk menjalankan logika berbeda berdasarkan konteks eksekusi.
  • Input: JSON melalui stdin
  • Output:
    • PreToolUse/PostToolUse/Stop/SubagentStop: Kemajuan ditampilkan dalam transkrip (Ctrl-R)
    • Notification/SessionEnd: Dicatat ke debug saja (--debug)
    • UserPromptSubmit/SessionStart: stdout ditambahkan sebagai konteks untuk Claude

Debugging

Pemecahan Masalah Dasar

Jika hooks Anda tidak bekerja:
  1. Periksa konfigurasi - Jalankan /hooks untuk melihat apakah hook Anda terdaftar
  2. Verifikasi sintaks - Pastikan pengaturan JSON Anda valid
  3. Uji perintah - Jalankan perintah hook secara manual terlebih dahulu
  4. Periksa izin - Pastikan skrip dapat dieksekusi
  5. Tinjau log - Gunakan claude --debug untuk melihat detail eksekusi hook
Masalah umum:
  • Kutipan tidak diloloskan - Gunakan \" di dalam string JSON
  • Matcher salah - Periksa nama alat cocok persis (peka huruf besar-kecil)
  • Perintah tidak ditemukan - Gunakan jalur lengkap untuk skrip

Debugging Lanjutan

Untuk masalah hook yang kompleks:
  1. Inspeksi eksekusi hook - Gunakan claude --debug untuk melihat hook terperinci eksekusi
  2. Validasi skema JSON - Uji input/output hook dengan alat eksternal
  3. Periksa variabel lingkungan - Verifikasi lingkungan Claude Code benar
  4. Uji kasus tepi - Coba hooks dengan jalur file atau input yang tidak biasa
  5. Monitor sumber daya sistem - Periksa kelelahan sumber daya selama eksekusi hook
  6. Gunakan logging terstruktur - Implementasikan logging dalam skrip hook Anda

Contoh Output Debug

Gunakan claude --debug untuk melihat detail eksekusi hook:
[DEBUG] Executing hooks for PostToolUse:Write
[DEBUG] Getting matching hook commands for PostToolUse with query: Write
[DEBUG] Found 1 hook matchers in settings
[DEBUG] Matched 1 hooks for query "Write"
[DEBUG] Found 1 hook commands to execute
[DEBUG] Executing hook command: <Your command> with timeout 60000ms
[DEBUG] Hook command completed with status 0: <Your stdout>
Pesan kemajuan muncul dalam mode transkrip (Ctrl-R) menampilkan:
  • Hook mana yang berjalan
  • Perintah yang dijalankan
  • Status sukses/gagal
  • Pesan output atau kesalahan