Langsung ke konten utama
Hooks adalah perintah shell yang ditentukan pengguna yang dijalankan pada titik-titik spesifik dalam siklus hidup Claude Code. Mereka memberikan kontrol deterministik atas perilaku Claude Code, memastikan tindakan tertentu selalu terjadi daripada mengandalkan LLM untuk memilih menjalankannya. Gunakan hooks untuk menegakkan aturan proyek, mengotomatisasi tugas berulang, dan mengintegrasikan Claude Code dengan alat yang sudah ada. Untuk keputusan yang memerlukan penilaian daripada aturan deterministik, Anda juga dapat menggunakan prompt-based hooks atau agent-based hooks yang menggunakan model Claude untuk mengevaluasi kondisi. Untuk cara lain memperluas Claude Code, lihat skills untuk memberikan Claude instruksi tambahan dan perintah yang dapat dieksekusi, subagents untuk menjalankan tugas dalam konteks terisolasi, dan plugins untuk mengemas ekstensi untuk dibagikan di seluruh proyek.
Panduan ini mencakup kasus penggunaan umum dan cara memulai. Untuk skema acara lengkap, format input/output JSON, dan fitur lanjutan seperti async hooks dan MCP tool hooks, lihat Hooks reference.

Siapkan hook pertama Anda

Untuk membuat hook, tambahkan blok hooks ke file pengaturan. Panduan ini membuat hook notifikasi desktop, sehingga Anda mendapat peringatan kapan pun Claude menunggu input Anda daripada menonton terminal.
1

Tambahkan hook ke pengaturan Anda

Buka ~/.claude/settings.json dan tambahkan hook Notification. Contoh di bawah menggunakan osascript untuk macOS; lihat Dapatkan notifikasi ketika Claude memerlukan input untuk perintah Linux dan Windows.
{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}
Jika file pengaturan Anda sudah memiliki kunci hooks, gabungkan entri Notification ke dalamnya daripada mengganti seluruh objek. Anda juga dapat meminta Claude untuk menulis hook untuk Anda dengan mendeskripsikan apa yang Anda inginkan di CLI.
2

Verifikasi konfigurasi

Ketik /hooks untuk membuka browser hooks. Anda akan melihat daftar semua acara hook yang tersedia, dengan hitungan di sebelah setiap acara yang memiliki hooks yang dikonfigurasi. Pilih Notification untuk mengonfirmasi hook baru Anda muncul dalam daftar. Memilih hook menampilkan detailnya: acara, matcher, jenis, file sumber, dan perintah.
3

Uji hook

Tekan Esc untuk kembali ke CLI. Minta Claude untuk melakukan sesuatu yang memerlukan izin, kemudian beralih dari terminal. Anda harus menerima notifikasi desktop.
Menu /hooks bersifat read-only. Untuk menambah, memodifikasi, atau menghapus hooks, edit JSON pengaturan Anda secara langsung atau minta Claude untuk membuat perubahan.

Apa yang dapat Anda otomatisasi

Hooks memungkinkan Anda menjalankan kode pada titik-titik kunci dalam siklus hidup Claude Code: format file setelah edit, blokir perintah sebelum dijalankan, kirim notifikasi ketika Claude memerlukan input, injeksi konteks saat awal sesi, dan banyak lagi. Untuk daftar lengkap acara hook, lihat Hooks reference. Setiap contoh mencakup blok konfigurasi siap pakai yang Anda tambahkan ke file pengaturan. Pola paling umum:

Dapatkan notifikasi ketika Claude memerlukan input

Dapatkan notifikasi desktop kapan pun Claude selesai bekerja dan memerlukan input Anda, sehingga Anda dapat beralih ke tugas lain tanpa memeriksa terminal. Hook ini menggunakan acara Notification, yang aktif ketika Claude menunggu input atau izin. Setiap tab di bawah menggunakan perintah notifikasi asli platform. Tambahkan ini ke ~/.claude/settings.json:
{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}

Auto-format kode setelah edit

Jalankan Prettier secara otomatis pada setiap file yang Claude edit, sehingga pemformatan tetap konsisten tanpa intervensi manual. Hook ini menggunakan acara PostToolUse dengan matcher Edit|Write, sehingga hanya berjalan setelah alat pengeditan file. Perintah mengekstrak jalur file yang diedit dengan jq dan meneruskannya ke Prettier. Tambahkan ini ke .claude/settings.json di root proyek Anda:
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
          }
        ]
      }
    ]
  }
}
Contoh Bash di halaman ini menggunakan jq untuk parsing JSON. Instal dengan brew install jq (macOS), apt-get install jq (Debian/Ubuntu), atau lihat jq downloads.

Blokir edit ke file yang dilindungi

Cegah Claude dari memodifikasi file sensitif seperti .env, package-lock.json, atau apa pun di .git/. Claude menerima umpan balik yang menjelaskan mengapa edit diblokir, sehingga dapat menyesuaikan pendekatannya. Contoh ini menggunakan file skrip terpisah yang dipanggil hook. Skrip memeriksa jalur file target terhadap daftar pola yang dilindungi dan keluar dengan kode 2 untuk memblokir edit.
1

Buat skrip hook

Simpan ini ke .claude/hooks/protect-files.sh:
#!/bin/bash
# protect-files.sh

INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')

PROTECTED_PATTERNS=(".env" "package-lock.json" ".git/")

for pattern in "${PROTECTED_PATTERNS[@]}"; do
  if [[ "$FILE_PATH" == *"$pattern"* ]]; then
    echo "Blocked: $FILE_PATH matches protected pattern '$pattern'" >&2
    exit 2
  fi
done

exit 0
2

Buat skrip dapat dieksekusi (macOS/Linux)

Skrip hook harus dapat dieksekusi agar Claude Code dapat menjalankannya:
chmod +x .claude/hooks/protect-files.sh
3

Daftarkan hook

Tambahkan hook PreToolUse ke .claude/settings.json yang menjalankan skrip sebelum panggilan alat Edit atau Write:
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
          }
        ]
      }
    ]
  }
}

Re-inject konteks setelah compaction

Ketika jendela konteks Claude penuh, compaction merangkum percakapan untuk membebaskan ruang. Ini dapat kehilangan detail penting. Gunakan hook SessionStart dengan matcher compact untuk re-inject konteks kritis setelah setiap compaction. Teks apa pun yang ditulis perintah Anda ke stdout ditambahkan ke konteks Claude. Contoh ini mengingatkan Claude tentang konvensi proyek dan pekerjaan terbaru. Tambahkan ini ke .claude/settings.json di root proyek Anda:
{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "compact",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Reminder: use Bun, not npm. Run bun test before committing. Current sprint: auth refactor.'"
          }
        ]
      }
    ]
  }
}
Anda dapat mengganti echo dengan perintah apa pun yang menghasilkan output dinamis, seperti git log --oneline -5 untuk menampilkan commit terbaru. Untuk injeksi konteks pada setiap awal sesi, pertimbangkan menggunakan CLAUDE.md sebagai gantinya. Untuk variabel lingkungan, lihat CLAUDE_ENV_FILE dalam referensi.

Audit perubahan konfigurasi

Lacak ketika file pengaturan atau skills berubah selama sesi. Acara ConfigChange aktif ketika proses eksternal atau editor memodifikasi file konfigurasi, sehingga Anda dapat mencatat perubahan untuk kepatuhan atau memblokir modifikasi yang tidak sah. Contoh ini menambahkan setiap perubahan ke log audit. Tambahkan ini ke ~/.claude/settings.json:
{
  "hooks": {
    "ConfigChange": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "jq -c '{timestamp: now | todate, source: .source, file: .file_path}' >> ~/claude-config-audit.log"
          }
        ]
      }
    ]
  }
}
Matcher memfilter berdasarkan jenis konfigurasi: user_settings, project_settings, local_settings, policy_settings, atau skills. Untuk memblokir perubahan agar tidak berlaku, keluar dengan kode 2 atau kembalikan {"decision": "block"}. Lihat ConfigChange reference untuk skema input lengkap.

Muat ulang lingkungan ketika direktori atau file berubah

Beberapa proyek menetapkan variabel lingkungan berbeda tergantung pada direktori mana Anda berada. Alat seperti direnv melakukan ini secara otomatis di shell Anda, tetapi alat Bash Claude tidak mengambil perubahan itu sendiri. Hook CwdChanged memperbaiki ini: ia berjalan setiap kali Claude mengubah direktori, sehingga Anda dapat memuat ulang variabel yang benar untuk lokasi baru. Hook menulis nilai yang diperbarui ke CLAUDE_ENV_FILE, yang Claude Code terapkan sebelum setiap perintah Bash. Tambahkan ini ke ~/.claude/settings.json:
{
  "hooks": {
    "CwdChanged": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "direnv export bash >> \"$CLAUDE_ENV_FILE\""
          }
        ]
      }
    ]
  }
}
Untuk bereaksi terhadap file spesifik daripada setiap perubahan direktori, gunakan FileChanged dengan matcher yang mencantumkan nama file yang akan dipantau (dipisahkan dengan pipa). matcher mengonfigurasi file mana yang akan dipantau dan memfilter hook mana yang berjalan. Contoh ini memantau .envrc dan .env untuk perubahan di direktori saat ini:
{
  "hooks": {
    "FileChanged": [
      {
        "matcher": ".envrc|.env",
        "hooks": [
          {
            "type": "command",
            "command": "direnv export bash >> \"$CLAUDE_ENV_FILE\""
          }
        ]
      }
    ]
  }
}
Lihat entri referensi CwdChanged dan FileChanged untuk skema input, output watchPaths, dan detail CLAUDE_ENV_FILE.

Auto-approve prompt izin tertentu

Lewati dialog persetujuan untuk panggilan alat yang selalu Anda izinkan. Contoh ini auto-approve ExitPlanMode, alat yang Claude panggil ketika selesai menyajikan rencana dan meminta untuk melanjutkan, sehingga Anda tidak diminta setiap kali rencana siap. Tidak seperti contoh kode keluar di atas, auto-approval memerlukan hook Anda untuk menulis keputusan JSON ke stdout. Hook PermissionRequest aktif ketika Claude Code akan menampilkan dialog izin, dan mengembalikan "behavior": "allow" menjawabnya atas nama Anda. Matcher membatasi hook ke ExitPlanMode saja, sehingga tidak ada prompt lain yang terpengaruh. Tambahkan ini ke ~/.claude/settings.json:
{
  "hooks": {
    "PermissionRequest": [
      {
        "matcher": "ExitPlanMode",
        "hooks": [
          {
            "type": "command",
            "command": "echo '{\"hookSpecificOutput\": {\"hookEventName\": \"PermissionRequest\", \"decision\": {\"behavior\": \"allow\"}}}'"
          }
        ]
      }
    ]
  }
}
Ketika hook menyetujui, Claude Code keluar dari plan mode dan mengembalikan mode izin apa pun yang aktif sebelum Anda memasuki plan mode. Transkrip menunjukkan “Allowed by PermissionRequest hook” di mana dialog akan muncul. Jalur hook selalu menjaga percakapan saat ini: tidak dapat menghapus konteks dan memulai sesi implementasi segar seperti yang dapat dilakukan dialog. Untuk menetapkan mode izin tertentu sebagai gantinya, output hook Anda dapat menyertakan array updatedPermissions dengan entri setMode. Nilai mode adalah mode izin apa pun seperti default, acceptEdits, atau bypassPermissions, dan destination: "session" menerapkannya hanya untuk sesi saat ini. Untuk beralih sesi ke acceptEdits, hook Anda menulis JSON ini ke stdout:
{
  "hookSpecificOutput": {
    "hookEventName": "PermissionRequest",
    "decision": {
      "behavior": "allow",
      "updatedPermissions": [
        { "type": "setMode", "mode": "acceptEdits", "destination": "session" }
      ]
    }
  }
}
Jaga matcher sesempit mungkin. Mencocokkan pada .* atau membiarkan matcher kosong akan auto-approve setiap prompt izin, termasuk penulisan file dan perintah shell. Lihat PermissionRequest reference untuk set lengkap bidang keputusan.

Cara kerja hooks

Acara hook aktif pada titik-titik siklus hidup spesifik di Claude Code. Ketika acara aktif, semua hook yang cocok berjalan secara paralel, dan perintah hook yang identik secara otomatis dideduplikasi. Tabel di bawah menunjukkan setiap acara dan kapan dipicu:
EventWhen it fires
SessionStartWhen a session begins or resumes
UserPromptSubmitWhen you submit a prompt, before Claude processes it
PreToolUseBefore a tool call executes. Can block it
PermissionRequestWhen a permission dialog appears
PermissionDeniedWhen a tool call is denied by the auto mode classifier. Return {retry: true} to tell the model it may retry the denied tool call
PostToolUseAfter a tool call succeeds
PostToolUseFailureAfter a tool call fails
NotificationWhen Claude Code sends a notification
SubagentStartWhen a subagent is spawned
SubagentStopWhen a subagent finishes
TaskCreatedWhen a task is being created via TaskCreate
TaskCompletedWhen a task is being marked as completed
StopWhen Claude finishes responding
StopFailureWhen the turn ends due to an API error. Output and exit code are ignored
TeammateIdleWhen an agent team teammate is about to go idle
InstructionsLoadedWhen a CLAUDE.md or .claude/rules/*.md file is loaded into context. Fires at session start and when files are lazily loaded during a session
ConfigChangeWhen a configuration file changes during a session
CwdChangedWhen the working directory changes, for example when Claude executes a cd command. Useful for reactive environment management with tools like direnv
FileChangedWhen a watched file changes on disk. The matcher field specifies which filenames to watch
WorktreeCreateWhen a worktree is being created via --worktree or isolation: "worktree". Replaces default git behavior
WorktreeRemoveWhen a worktree is being removed, either at session exit or when a subagent finishes
PreCompactBefore context compaction
PostCompactAfter context compaction completes
ElicitationWhen an MCP server requests user input during a tool call
ElicitationResultAfter a user responds to an MCP elicitation, before the response is sent back to the server
SessionEndWhen a session terminates
Setiap hook memiliki type yang menentukan cara menjalankannya. Sebagian besar hooks menggunakan "type": "command", yang menjalankan perintah shell. Tiga jenis lain tersedia:

Baca input dan kembalikan output

Hooks berkomunikasi dengan Claude Code melalui stdin, stdout, stderr, dan kode keluar. Ketika acara aktif, Claude Code meneruskan data spesifik acara sebagai JSON ke stdin skrip Anda. Skrip Anda membaca data itu, melakukan pekerjaan, dan memberi tahu Claude Code apa yang harus dilakukan selanjutnya melalui kode keluar.

Hook input

Setiap acara mencakup bidang umum seperti session_id dan cwd, tetapi setiap jenis acara menambahkan data berbeda. Misalnya, ketika Claude menjalankan perintah Bash, hook PreToolUse menerima sesuatu seperti ini di stdin:
{
  "session_id": "abc123",          // unique ID for this session
  "cwd": "/Users/sarah/myproject", // working directory when the event fired
  "hook_event_name": "PreToolUse", // which event triggered this hook
  "tool_name": "Bash",             // the tool Claude is about to use
  "tool_input": {                  // the arguments Claude passed to the tool
    "command": "npm test"          // for Bash, this is the shell command
  }
}
Skrip Anda dapat mengurai JSON itu dan bertindak atas bidang apa pun. Hook UserPromptSubmit mendapatkan teks prompt sebagai gantinya, hook SessionStart mendapatkan source (startup, resume, clear, compact), dan seterusnya. Lihat Common input fields dalam referensi untuk bidang bersama, dan bagian setiap acara untuk skema spesifik acara.

Hook output

Skrip Anda memberi tahu Claude Code apa yang harus dilakukan selanjutnya dengan menulis ke stdout atau stderr dan keluar dengan kode spesifik. Misalnya, hook PreToolUse yang ingin memblokir perintah:
#!/bin/bash
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command')

if echo "$COMMAND" | grep -q "drop table"; then
  echo "Blocked: dropping tables is not allowed" >&2  # stderr becomes Claude's feedback
  exit 2 # exit 2 = block the action
fi

exit 0  # exit 0 = let it proceed
Kode keluar menentukan apa yang terjadi selanjutnya:
  • Exit 0: tindakan berlanjut. Untuk hook UserPromptSubmit dan SessionStart, apa pun yang Anda tulis ke stdout ditambahkan ke konteks Claude.
  • Exit 2: tindakan diblokir. Tulis alasan ke stderr, dan Claude menerimanya sebagai umpan balik sehingga dapat menyesuaikan.
  • Kode keluar lainnya: tindakan berlanjut. Stderr dicatat tetapi tidak ditampilkan ke Claude. Alihkan mode verbose dengan Ctrl+O untuk melihat pesan ini dalam transkrip.

Structured JSON output

Kode keluar memberi Anda dua opsi: izinkan atau blokir. Untuk kontrol lebih, keluar 0 dan cetak objek JSON ke stdout sebagai gantinya.
Gunakan exit 2 untuk memblokir dengan pesan stderr, atau exit 0 dengan JSON untuk kontrol terstruktur. Jangan campur: Claude Code mengabaikan JSON ketika Anda exit 2.
Misalnya, hook PreToolUse dapat menolak panggilan alat dan memberi tahu Claude mengapa, atau meningkatkannya ke pengguna untuk persetujuan:
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "Use rg instead of grep for better performance"
  }
}
Claude Code membaca permissionDecision dan membatalkan panggilan alat, kemudian memberi makan permissionDecisionReason kembali ke Claude sebagai umpan balik. Tiga opsi ini spesifik untuk PreToolUse:
  • "allow": lanjutkan tanpa menampilkan prompt izin interaktif. Aturan deny dan ask, termasuk daftar deny yang dikelola perusahaan, masih berlaku
  • "deny": batalkan panggilan alat dan kirim alasan ke Claude
  • "ask": tampilkan prompt izin kepada pengguna seperti biasa
Mengembalikan "allow" melewati prompt interaktif tetapi tidak mengesampingkan aturan izin. Jika aturan deny cocok dengan panggilan alat, panggilan diblokir bahkan ketika hook Anda mengembalikan "allow". Jika aturan ask cocok, pengguna masih diminta. Ini berarti aturan deny dari cakupan pengaturan apa pun, termasuk pengaturan terkelola, selalu mengambil alih persetujuan hook. Acara lain menggunakan pola keputusan berbeda. Misalnya, hook PostToolUse dan Stop menggunakan bidang decision: "block" tingkat atas, sementara PermissionRequest menggunakan hookSpecificOutput.decision.behavior. Lihat summary table dalam referensi untuk rincian lengkap berdasarkan acara. Untuk hook UserPromptSubmit, gunakan additionalContext sebagai gantinya untuk menyuntikkan teks ke dalam konteks Claude. Hook berbasis prompt (type: "prompt") menangani output secara berbeda: lihat Prompt-based hooks.

Filter hooks dengan matchers

Tanpa matcher, hook aktif pada setiap kemunculan acaranya. Matchers memungkinkan Anda mempersempit itu. Misalnya, jika Anda ingin menjalankan formatter hanya setelah edit file (bukan setelah setiap panggilan alat), tambahkan matcher ke hook PostToolUse Anda:
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          { "type": "command", "command": "prettier --write ..." }
        ]
      }
    ]
  }
}
Matcher "Edit|Write" adalah pola regex yang cocok dengan nama alat. Hook hanya aktif ketika Claude menggunakan alat Edit atau Write, bukan ketika menggunakan Bash, Read, atau alat lainnya. Setiap jenis acara cocok pada bidang spesifik. Matchers mendukung string tepat dan pola regex:
AcaraApa yang difilter matcherContoh nilai matcher
PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequestnama alatBash, Edit|Write, mcp__.*
SessionStartcara sesi dimulaistartup, resume, clear, compact
SessionEndmengapa sesi berakhirclear, resume, logout, prompt_input_exit, bypass_permissions_disabled, other
Notificationjenis notifikasipermission_prompt, idle_prompt, auth_success, elicitation_dialog
SubagentStartjenis agenBash, Explore, Plan, atau nama agen khusus
PreCompact, PostCompactapa yang memicu compactionmanual, auto
SubagentStopjenis agennilai yang sama seperti SubagentStart
ConfigChangesumber konfigurasiuser_settings, project_settings, local_settings, policy_settings, skills
StopFailurejenis kesalahanrate_limit, authentication_failed, billing_error, invalid_request, server_error, max_output_tokens, unknown
InstructionsLoadedalasan pemuatansession_start, nested_traversal, path_glob_match, include, compact
Elicitationnama server MCPnama server MCP yang dikonfigurasi Anda
ElicitationResultnama server MCPnilai yang sama seperti Elicitation
FileChangednama file (basename file yang berubah).envrc, .env, nama file apa pun yang ingin Anda pantau
UserPromptSubmit, Stop, TeammateIdle, TaskCompleted, WorktreeCreate, WorktreeRemove, CwdChangedtidak ada dukungan matcherselalu aktif pada setiap kemunculan
Beberapa contoh lagi menunjukkan matchers pada jenis acara berbeda:
Cocokkan hanya panggilan alat Bash dan catat setiap perintah ke file. Acara PostToolUse aktif setelah perintah selesai, jadi tool_input.command berisi apa yang berjalan. Hook menerima data acara sebagai JSON di stdin, dan jq -r '.tool_input.command' mengekstrak hanya string perintah, yang >> tambahkan ke file log:
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.command' >> ~/.claude/command-log.txt"
          }
        ]
      }
    ]
  }
}
Untuk sintaks matcher lengkap, lihat Hooks reference.

Konfigurasi lokasi hook

Di mana Anda menambahkan hook menentukan cakupannya:
LokasiCakupanDapat Dibagikan
~/.claude/settings.jsonSemua proyek AndaTidak, lokal ke mesin Anda
.claude/settings.jsonProyek tunggalYa, dapat dikomit ke repo
.claude/settings.local.jsonProyek tunggalTidak, gitignored
Pengaturan kebijakan terkelolaSeluruh organisasiYa, dikendalikan admin
Plugin hooks/hooks.jsonKetika plugin diaktifkanYa, dikemas dengan plugin
Skill atau agent frontmatterSaat skill atau agent aktifYa, didefinisikan dalam file komponen
Jalankan /hooks di Claude Code untuk menjelajahi semua hooks yang dikonfigurasi dikelompokkan berdasarkan acara. Untuk menonaktifkan semua hooks sekaligus, atur "disableAllHooks": true dalam file pengaturan Anda. Jika Anda mengedit file pengaturan secara langsung saat Claude Code berjalan, file watcher biasanya mengambil perubahan hook secara otomatis.

Prompt-based hooks

Untuk keputusan yang memerlukan penilaian daripada aturan deterministik, gunakan hook type: "prompt". Daripada menjalankan perintah shell, Claude Code mengirim prompt Anda dan data input hook ke model Claude (Haiku secara default) untuk membuat keputusan. Anda dapat menentukan model berbeda dengan bidang model jika Anda memerlukan kemampuan lebih. Satu-satunya pekerjaan model adalah mengembalikan keputusan ya/tidak sebagai JSON:
  • "ok": true: tindakan berlanjut
  • "ok": false: tindakan diblokir. "reason" model diberi makan kembali ke Claude sehingga dapat menyesuaikan.
Contoh ini menggunakan hook Stop untuk menanyakan kepada model apakah semua tugas yang diminta selesai. Jika model mengembalikan "ok": false, Claude terus bekerja dan menggunakan reason sebagai instruksi berikutnya:
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "prompt",
            "prompt": "Check if all tasks are complete. If not, respond with {\"ok\": false, \"reason\": \"what remains to be done\"}."
          }
        ]
      }
    ]
  }
}
Untuk opsi konfigurasi lengkap, lihat Prompt-based hooks dalam referensi.

Agent-based hooks

Ketika verifikasi memerlukan inspeksi file atau menjalankan perintah, gunakan hook type: "agent". Tidak seperti hook prompt yang membuat panggilan LLM tunggal, hook agent menelurkan subagent yang dapat membaca file, mencari kode, dan menggunakan alat lain untuk memverifikasi kondisi sebelum mengembalikan keputusan. Hook agent menggunakan format respons "ok" / "reason" yang sama seperti hook prompt, tetapi dengan timeout default lebih lama 60 detik dan hingga 50 putaran penggunaan alat. Contoh ini memverifikasi bahwa tes lulus sebelum memungkinkan Claude berhenti:
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "agent",
            "prompt": "Verify that all unit tests pass. Run the test suite and check the results. $ARGUMENTS",
            "timeout": 120
          }
        ]
      }
    ]
  }
}
Gunakan hook prompt ketika data input hook saja cukup untuk membuat keputusan. Gunakan hook agent ketika Anda perlu memverifikasi sesuatu terhadap keadaan aktual codebase. Untuk opsi konfigurasi lengkap, lihat Agent-based hooks dalam referensi.

HTTP hooks

Gunakan hook type: "http" untuk POST data acara ke endpoint HTTP daripada menjalankan perintah shell. Endpoint menerima JSON yang sama yang diterima hook perintah di stdin, dan mengembalikan hasil melalui badan respons HTTP menggunakan format JSON yang sama. HTTP hooks berguna ketika Anda ingin server web, fungsi cloud, atau layanan eksternal menangani logika hook: misalnya, layanan audit bersama yang mencatat acara penggunaan alat di seluruh tim. Contoh ini memposting setiap penggunaan alat ke layanan logging lokal:
{
  "hooks": {
    "PostToolUse": [
      {
        "hooks": [
          {
            "type": "http",
            "url": "http://localhost:8080/hooks/tool-use",
            "headers": {
              "Authorization": "Bearer $MY_TOKEN"
            },
            "allowedEnvVars": ["MY_TOKEN"]
          }
        ]
      }
    ]
  }
}
Endpoint harus mengembalikan badan respons JSON menggunakan output format yang sama seperti hook perintah. Untuk memblokir panggilan alat, kembalikan respons 2xx dengan bidang hookSpecificOutput yang sesuai. Kode status HTTP saja tidak dapat memblokir tindakan. Nilai header mendukung interpolasi variabel lingkungan menggunakan sintaks $VAR_NAME atau ${VAR_NAME}. Hanya variabel yang tercantum dalam array allowedEnvVars yang diselesaikan; semua referensi $VAR lainnya tetap kosong. Untuk opsi konfigurasi lengkap dan penanganan respons, lihat HTTP hooks dalam referensi.

Keterbatasan dan troubleshooting

Keterbatasan

  • Hook perintah berkomunikasi melalui stdout, stderr, dan kode keluar saja. Mereka tidak dapat memicu perintah atau panggilan alat secara langsung. HTTP hooks berkomunikasi melalui badan respons sebagai gantinya.
  • Timeout hook adalah 10 menit secara default, dapat dikonfigurasi per hook dengan bidang timeout (dalam detik).
  • Hook PostToolUse tidak dapat membatalkan tindakan karena alat sudah dieksekusi.
  • Hook PermissionRequest tidak aktif dalam non-interactive mode (-p). Gunakan hook PreToolUse untuk keputusan izin otomatis.
  • Hook Stop aktif kapan pun Claude selesai merespons, bukan hanya pada penyelesaian tugas. Mereka tidak aktif pada interupsi pengguna. Kesalahan API menjalankan StopFailure sebagai gantinya.

Hook tidak aktif

Hook dikonfigurasi tetapi tidak pernah dieksekusi.
  • Jalankan /hooks dan konfirmasi hook muncul di bawah acara yang benar
  • Periksa bahwa pola matcher cocok dengan nama alat dengan tepat (matcher peka huruf besar-kecil)
  • Verifikasi Anda memicu jenis acara yang benar (misalnya, PreToolUse aktif sebelum eksekusi alat, PostToolUse aktif setelah)
  • Jika menggunakan hook PermissionRequest dalam mode non-interaktif (-p), beralih ke PreToolUse sebagai gantinya

Hook error dalam output

Anda melihat pesan seperti “PreToolUse hook error: …” dalam transkrip.
  • Skrip Anda keluar dengan kode non-nol secara tidak terduga. Uji secara manual dengan menyalurkan JSON sampel:
    echo '{"tool_name":"Bash","tool_input":{"command":"ls"}}' | ./my-hook.sh
    echo $?  # Check the exit code
    
  • Jika Anda melihat “command not found”, gunakan jalur absolut atau $CLAUDE_PROJECT_DIR untuk mereferensikan skrip
  • Jika Anda melihat “jq: command not found”, instal jq atau gunakan Python/Node.js untuk parsing JSON
  • Jika skrip tidak berjalan sama sekali, buat dapat dieksekusi: chmod +x ./my-hook.sh

/hooks menunjukkan tidak ada hooks yang dikonfigurasi

Anda mengedit file pengaturan tetapi hooks tidak muncul dalam menu.
  • Edit file biasanya diambil secara otomatis. Jika belum muncul setelah beberapa detik, file watcher mungkin melewatkan perubahan: mulai ulang sesi Anda untuk memaksa reload.
  • Verifikasi JSON Anda valid (trailing commas dan comments tidak diizinkan)
  • Konfirmkan file pengaturan berada di lokasi yang benar: .claude/settings.json untuk hook proyek, ~/.claude/settings.json untuk hook global

Stop hook berjalan selamanya

Claude terus bekerja dalam loop tak terbatas daripada berhenti. Skrip Stop hook Anda perlu memeriksa apakah sudah memicu kelanjutan. Parsing bidang stop_hook_active dari input JSON dan keluar lebih awal jika true:
#!/bin/bash
INPUT=$(cat)
if [ "$(echo "$INPUT" | jq -r '.stop_hook_active')" = "true" ]; then
  exit 0  # Allow Claude to stop
fi
# ... rest of your hook logic

JSON validation failed

Claude Code menampilkan kesalahan parsing JSON meskipun skrip hook Anda mengeluarkan JSON yang valid. Ketika Claude Code menjalankan hook, ia menelurkan shell yang bersumber dari profil Anda (~/.zshrc atau ~/.bashrc). Jika profil Anda berisi pernyataan echo tanpa syarat, output itu ditambahkan ke JSON hook Anda:
Shell ready on arm64
{"decision": "block", "reason": "Not allowed"}
Claude Code mencoba mengurai ini sebagai JSON dan gagal. Untuk memperbaiki ini, bungkus pernyataan echo dalam profil shell Anda sehingga hanya berjalan di shell interaktif:
# In ~/.zshrc or ~/.bashrc
if [[ $- == *i* ]]; then
  echo "Shell ready"
fi
Variabel $- berisi flag shell, dan i berarti interaktif. Hooks berjalan di shell non-interaktif, jadi echo dilewati.

Teknik debug

Alihkan mode verbose dengan Ctrl+O untuk melihat output hook dalam transkrip, atau jalankan claude --debug untuk detail eksekusi lengkap termasuk hook mana yang cocok dan kode keluar mereka.

Pelajari lebih lanjut