Siklus hidup hook
Hooks dijalankan pada titik-titik tertentu selama sesi Claude Code. Ketika event dijalankan dan matcher cocok, Claude Code meneruskan konteks JSON tentang event ke handler hook Anda. Untuk command hooks, input tiba di stdin. Untuk HTTP hooks, input tiba sebagai badan permintaan POST. Handler Anda kemudian dapat memeriksa input, mengambil tindakan, dan secara opsional mengembalikan keputusan. Events jatuh ke dalam tiga cadence:- sekali per sesi:
SessionStartdanSessionEnd - sekali per turn:
UserPromptSubmit,Stop, danStopFailure - pada setiap pemanggilan tool di dalam loop agentic:
PreToolUsedanPostToolUse
Bagaimana hook diselesaikan
Untuk melihat bagaimana potongan-potongan ini cocok bersama, pertimbangkan hookPreToolUse ini yang memblokir perintah shell yang merusak. matcher mempersempit ke pemanggilan tool Bash dan kondisi if mempersempit lebih lanjut ke perintah Bash yang cocok dengan rm *, jadi block-rm.sh hanya spawn ketika kedua filter cocok:
permissionDecision dari "deny" jika berisi rm -rf:
Bash "rm -rf /tmp/build". Inilah yang terjadi:
1
Event dijalankan
Event
PreToolUse dijalankan. Claude Code mengirimkan input tool sebagai JSON di stdin ke hook:2
Matcher memeriksa
Matcher
"Bash" cocok dengan nama tool, jadi grup hook ini diaktifkan. Jika Anda menghilangkan matcher atau menggunakan "*", grup diaktifkan pada setiap kemunculan event.3
Kondisi if memeriksa
Kondisi
if "Bash(rm *)" cocok karena rm -rf /tmp/build adalah subperintah yang cocok dengan rm *, jadi handler ini spawn. Jika perintah telah npm test, pemeriksaan if akan gagal dan block-rm.sh tidak akan pernah dijalankan, menghindari overhead spawn proses. Bidang if bersifat opsional; tanpanya, setiap handler dalam grup yang cocok dijalankan.4
Handler hook dijalankan
Skrip memeriksa perintah lengkap dan menemukan Jika perintah telah menjadi varian
rm -rf, jadi itu mencetak keputusan ke stdout:rm yang lebih aman seperti rm file.txt, skrip akan mencapai exit 0 sebagai gantinya. Kode keluar 0 tanpa output berarti hook tidak memiliki keputusan untuk dilaporkan, jadi pemanggilan tool berlanjut melalui alur izin normal. Hook dapat menolak pemanggilan, tetapi tetap diam tidak menyetujuinya.5
Claude Code bertindak atas hasil
Claude Code membaca keputusan JSON, memblokir pemanggilan tool, dan menunjukkan Claude alasannya.
Konfigurasi
Hooks didefinisikan dalam file pengaturan JSON. Konfigurasi memiliki tiga tingkat nesting:- Pilih hook event untuk merespons, seperti
PreToolUseatauStop - Tambahkan matcher group untuk memfilter kapan dijalankan, seperti “hanya untuk tool Bash”
- Tentukan satu atau lebih hook handlers untuk dijalankan saat cocok
Halaman ini menggunakan istilah spesifik untuk setiap tingkat: hook event untuk titik siklus hidup, matcher group untuk filter, dan hook handler untuk perintah shell, endpoint HTTP, tool MCP, prompt, atau agent yang dijalankan. “Hook” sendiri merujuk pada fitur umum.
Lokasi hook
Tempat Anda mendefinisikan hook menentukan cakupannya:
Untuk detail tentang resolusi file pengaturan, lihat settings. Administrator enterprise dapat menggunakan
allowManagedHooksOnly untuk memblokir hooks pengguna, proyek, dan plugin. Hooks dari plugins yang dipaksa-aktifkan dalam pengaturan terkelola enabledPlugins dikecualikan, jadi administrator dapat mendistribusikan hooks yang telah diverifikasi melalui marketplace organisasi. Lihat Hook configuration.
Pola matcher
Bidangmatcher memfilter kapan hooks dijalankan. Bagaimana matcher dievaluasi tergantung pada karakter yang dikandungnya:
Matcher pada jalur ekspresi reguler diuji dengan
RegExp.prototype.test JavaScript, yang berhasil pada kecocokan di mana pun dalam nilai. Edit.* cocok dengan Edit dan NotebookEdit; bungkus pola dalam ^ dan $, seperti ^Edit$, ketika Anda memerlukan kecocokan seluruh string.
Pemisah koma dan toleransi whitespace di sekitarnya memerlukan Claude Code v2.1.191 atau lebih baru.
Tanda hubung dalam set exact-match memerlukan Claude Code v2.1.195 atau lebih baru. Pada versi sebelumnya, nama dengan tanda hubung seperti code-reviewer dievaluasi sebagai ekspresi reguler yang tidak berlabuh, jadi juga dijalankan untuk senior-code-reviewer; labuhnya sebagai ^code-reviewer$ pada versi tersebut untuk mencocokkan hanya nama itu.
FileChanged dan StopFailure menggunakan set exact-match yang lebih sempit dari huruf, digit, _, dan | saja. Tanda hubung, spasi, atau koma dalam matcher untuk dua event itu membuat tetap pada jalur ekspresi reguler, dan hanya | yang memisahkan alternatif. Setiap event lain dengan dukungan matcher dalam tabel yang mengikuti menerima | atau ,.
Event FileChanged tidak mengikuti aturan ini saat membangun daftar watch-nya. Lihat FileChanged.
Setiap tipe event cocok pada bidang yang berbeda:
Matcher dijalankan terhadap bidang dari JSON input yang Claude Code kirimkan ke hook Anda di stdin. Untuk tool events, bidang itu adalah
tool_name. Setiap bagian hook event mencantumkan set lengkap nilai matcher dan skema input untuk event itu.
Contoh ini menjalankan skrip linting hanya ketika Claude menulis atau mengedit file:
UserPromptSubmit, PostToolBatch, Stop, TeammateIdle, TaskCreated, TaskCompleted, WorktreeCreate, WorktreeRemove, MessageDisplay, dan CwdChanged tidak mendukung matchers dan selalu dijalankan pada setiap kemunculan. Jika Anda menambahkan bidang matcher ke event ini, itu akan diabaikan secara diam-diam.
Untuk tool events, Anda dapat memfilter lebih sempit dengan menetapkan bidang if pada handler hook individual. if menggunakan sintaks aturan izin untuk mencocokkan terhadap nama tool dan argumen bersama-sama, jadi "Bash(git *)" dijalankan ketika subperintah apa pun dari input Bash cocok dengan git * dan "Edit(*.ts)" dijalankan hanya untuk file TypeScript.
Cocokkan MCP tools
Tool server MCP muncul sebagai tool reguler dalam tool events (PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest, PermissionDenied), jadi Anda dapat mencocokkannya dengan cara yang sama seperti Anda mencocokkan nama tool lainnya.
MCP tools mengikuti pola penamaan mcp__<server>__<tool>, misalnya:
mcp__memory__create_entities: tool create entities dari Memory servermcp__filesystem__read_file: tool read file dari Filesystem servermcp__github__search_repositories: tool search dari GitHub server
.* ke awalan server. .* diperlukan: matcher seperti mcp__memory atau mcp__brave-search hanya berisi karakter exact-match, jadi dibandingkan sebagai string yang tepat dan tidak cocok dengan tool apa pun.
mcp__memory__.*cocok dengan semua tools dari servermemorymcp__brave-search__.*cocok dengan semua tools dari server yang namanya berisi tanda hubungmcp__.*__write.*cocok dengan tool apa pun yang namanya dimulai denganwritedari server apa pun
mcp__brave-search dievaluasi sebagai ekspresi reguler yang tidak berlabuh dan cocok dengan setiap tool dari server itu. Bentuk mcp__brave-search__.* bekerja pada setiap versi.
Tools dari plugin-bundled MCP server menggunakan segmen server yang dibatasi yang mencakup nama plugin: mcp__plugin_<plugin-name>_<server-name>__<tool>. Matcher yang ditulis terhadap kunci server bare tidak pernah dijalankan untuk tools ini. Untuk plugin bernama my-plugin yang membundel server di bawah kunci db, tool query muncul sebagai mcp__plugin_my-plugin_db__query, jadi matcher untuk setiap tool dari server itu adalah mcp__plugin_my-plugin_db__.*. Gunakan nama tool yang dibatasi yang sama dalam bidang if handler. Lihat Plugin-provided MCP servers untuk bagaimana nama yang dibatasi dibangun.
Contoh ini mencatat semua operasi memory server dan memvalidasi operasi write dari server MCP apa pun:
Bidang hook handler
Setiap objek dalam arrayhooks inner adalah hook handler: perintah shell, endpoint HTTP, tool MCP, prompt LLM, atau agent yang dijalankan saat matcher cocok. Ada lima tipe:
- Command hooks (
type: "command"): jalankan perintah shell. Skrip Anda menerima JSON input event di stdin dan mengkomunikasikan hasil kembali melalui kode keluar dan stdout. - HTTP hooks (
type: "http"): kirimkan JSON input event sebagai permintaan HTTP POST ke URL. Endpoint mengkomunikasikan hasil kembali melalui badan respons menggunakan format JSON output yang sama seperti command hooks. - MCP tool hooks (
type: "mcp_tool"): panggil tool pada MCP server yang sudah terhubung. Output teks tool diperlakukan seperti command-hook stdout. - Prompt hooks (
type: "prompt"): kirimkan prompt ke model Claude untuk evaluasi single-turn. Model mengembalikan keputusan yes/no sebagai JSON. Lihat Prompt-based hooks. - Agent hooks (
type: "agent"): spawn subagent yang dapat menggunakan tools seperti Read, Grep, dan Glob untuk memverifikasi kondisi sebelum mengembalikan keputusan. Agent hooks adalah eksperimental dan mungkin berubah. Lihat Agent-based hooks.
args, dan HTTP hooks dideduplikasi berdasarkan URL.
Handlers dijalankan di direktori saat ini dengan lingkungan Claude Code. Variabel lingkungan $CLAUDE_CODE_REMOTE diatur ke "true" di lingkungan web jarak jauh dan tidak diatur di CLI lokal. Mulai dari v2.1.199, $CLAUDE_CODE_BRIDGE_SESSION_ID diatur ke Remote Control session ID saat sesi lokal memiliki koneksi Remote Control yang aktif.
Bidang umum
Bidang-bidang ini berlaku untuk semua tipe hook:
Bidang
if menyimpan tepat satu aturan izin. Tidak ada sintaks &&, ||, atau list untuk menggabungkan aturan; untuk menerapkan beberapa kondisi, tentukan handler hook terpisah untuk masing-masing.
Untuk pola Bash, apakah hook command Anda dijalankan tergantung pada bentuk pola dan perintah Bash yang Claude panggil. Penugasan VAR=value terkemuka dihapus sebelum pencocokan.
Filter juga gagal terbuka, menjalankan hook Anda terlepas dari pola, ketika perintah Bash tidak dapat diurai. Karena filter
if adalah best-effort, gunakan sistem izin daripada hook untuk memberlakukan allow atau deny yang keras.
Bidang command hook
Selain bidang umum, command hooks menerima bidang-bidang ini:
Hook command dijalankan sebagai exec form ketika
args diatur, dan shell form ketika args dihilangkan. Atur args setiap kali hook mereferensikan path placeholder, karena setiap elemen dilewatkan sebagai satu argumen tanpa quoting. Hilangkan args ketika Anda memerlukan fitur shell seperti pipes atau &&, atau ketika tidak ada kekhawatiran yang berlaku.
Exec form dijalankan ketika args ada. Claude Code menyelesaikan command sebagai executable di PATH dan spawn-nya secara langsung dengan args sebagai vektor argumen. Tidak ada shell, jadi setiap elemen args adalah satu argumen persis seperti yang ditulis, dan path placeholders seperti ${CLAUDE_PLUGIN_ROOT} disubstitusi ke dalam command dan ke dalam setiap elemen args sebagai string biasa. Karakter khusus seperti apostrophe, $, dan backticks melewati verbatim karena tidak ada shell untuk menginterpretasinya. Tidak ada tokenisasi shell yang terjadi di platform apa pun.
Shell form dijalankan ketika args tidak ada. String command dilewatkan ke shell: sh -c di macOS dan Linux, Git Bash di Windows, atau PowerShell ketika Git Bash tidak diinstal. Atur bidang shell untuk memilih secara eksplisit. Shell melakukan tokenisasi string, memperluas variabel, dan menginterpretasi pipes, &&, redirects, dan globs.
Di Windows, exec form memerlukan
command untuk diselesaikan ke executable nyata seperti .exe. Shim .cmd dan .bat yang npm, npx, eslint, dan tools lainnya instal di node_modules/.bin bukan executables dan tidak dapat di-spawn tanpa shell. Untuk menjalankannya dalam exec form, panggil skrip yang mendasar dengan node secara langsung, misalnya "command": "node", "args": ["${CLAUDE_PLUGIN_ROOT}/node_modules/eslint/bin/eslint.js"]. Pola node plus script-path bekerja di setiap platform karena node.exe adalah binary nyata. Untuk menjalankan shim .cmd atau .bat berdasarkan nama, gunakan shell form.CLAUDE_PROJECT_DIR, CLAUDE_PLUGIN_ROOT, dan CLAUDE_PLUGIN_DATA pada proses yang di-spawn, jadi skrip dapat membaca process.env.CLAUDE_PLUGIN_ROOT terlepas dari bagaimana itu diluncurkan.
Plugin hooks juga mensubstitusi nilai ${user_config.*}, dalam exec form saja: nilai disubstitusi ke dalam command dan ke dalam setiap elemen args sebagai string biasa, jadi tidak ada shell yang mem-parse ulangnya.
Hook plugin bentuk shell yang command-nya mereferensikan ${user_config.*} gagal dengan error daripada menjalankan. Untuk menggunakan nilai opsi dari hook bentuk shell, baca variabel lingkungan $CLAUDE_PLUGIN_OPTION_<KEY>, seperti $CLAUDE_PLUGIN_OPTION_WEBHOOK_URL untuk opsi webhook_url, atau atur args untuk beralih hook ke exec form. Sebelum v2.1.207, hook plugin bentuk shell juga mensubstitusi ${user_config.*}.
Dalam exec form,
command adalah nama executable atau path saja. Jika command adalah nama bare tanpa path separator dan berisi whitespace bersama args, Claude Code mencatat warning karena spawn akan gagal: tidak ada executable bernama node script.js. Pindahkan token ekstra ke dalam args. Path absolut dengan spasi, seperti C:\Program Files\nodejs\node.exe, adalah executable tunggal yang valid dan tidak memicu warning.Bidang HTTP hook
Selain bidang umum, HTTP hooks menerima bidang-bidang ini:
Claude Code mengirimkan JSON input hook sebagai badan permintaan POST dengan
Content-Type: application/json. Badan respons menggunakan format JSON output yang sama seperti command hooks.
Penanganan kesalahan berbeda dari command hooks: respons non-2xx, kegagalan koneksi, dan timeout semuanya menghasilkan kesalahan non-blocking yang memungkinkan eksekusi berlanjut. Untuk memblokir pemanggilan tool atau menolak izin, kembalikan respons 2xx dengan badan JSON yang berisi decision: "block" atau hookSpecificOutput dengan permissionDecision: "deny".
Contoh ini mengirimkan event PreToolUse ke layanan validasi lokal, mengautentikasi dengan token dari variabel lingkungan MY_TOKEN:
Bidang MCP tool hook
Selain bidang umum, MCP tool hooks menerima bidang-bidang ini:
Output teks tool diperlakukan seperti command-hook stdout: jika itu diurai sebagai JSON output yang valid, itu diproses sebagai keputusan, jika tidak, itu ditampilkan sebagai teks biasa. Jika server bernama tidak terhubung, atau tool mengembalikan
isError: true, hook menghasilkan kesalahan non-blocking dan eksekusi berlanjut.
MCP tool hooks tersedia pada setiap hook event setelah Claude Code terhubung ke server MCP Anda. SessionStart dan Setup biasanya dijalankan sebelum server selesai terhubung, jadi hooks pada event tersebut harus mengharapkan kesalahan “not connected” pada run pertama.
Contoh ini memanggil tool security_scan pada server MCP my_server setelah setiap Write atau Edit, melewatkan path file yang diedit:
Bidang prompt dan agent hook
Selain bidang umum, prompt dan agent hooks menerima bidang-bidang ini:Referensi skrip berdasarkan path
Gunakan placeholders ini untuk mereferensikan skrip hook relatif terhadap akar proyek atau plugin, terlepas dari direktori kerja saat hook dijalankan:${CLAUDE_PROJECT_DIR}: akar proyek. Claude Code juga menetapkan variabel ini dalam lingkungan stdio MCP servers dan plugin LSP servers.${CLAUDE_PLUGIN_ROOT}: direktori instalasi plugin, untuk skrip yang dibundel dengan plugin. Berubah pada setiap pembaruan plugin.${CLAUDE_PLUGIN_DATA}: direktori data persisten plugin, untuk dependensi dan status yang harus bertahan pembaruan plugin.
args sebagai satu argumen tanpa tokenisasi shell, jadi paths dengan spasi atau karakter khusus tidak memerlukan quoting. Dalam shell form, bungkus setiap placeholder dalam tanda kutip ganda.
- Skrip proyek
- Skrip plugin
Contoh ini menggunakan
${CLAUDE_PROJECT_DIR} untuk menjalankan pemeriksa gaya dari direktori .claude/hooks/ proyek setelah pemanggilan tool Write atau Edit apa pun:Hooks dalam skills dan agents
Selain file pengaturan dan plugin, hooks dapat didefinisikan langsung dalam skills dan subagents menggunakan frontmatter. Hooks ini dibatasi pada siklus hidup komponen dan hanya dijalankan ketika komponen itu aktif. Semua hook events didukung. Untuk subagents,Stop hooks secara otomatis dikonversi ke SubagentStop karena itu adalah event yang dijalankan ketika subagent selesai.
Hooks menggunakan format konfigurasi yang sama seperti hooks berbasis pengaturan tetapi dibatasi pada masa hidup komponen dan dibersihkan saat selesai.
Skill ini mendefinisikan hook PreToolUse yang menjalankan skrip validasi keamanan sebelum setiap perintah Bash:
Menu /hooks
Ketik /hooks di Claude Code untuk membuka browser hooks read-only. Menu menampilkan setiap hook event dengan jumlah hooks yang dikonfigurasi, memungkinkan Anda menggali ke dalam matchers, dan menampilkan detail lengkap setiap hook handler. Gunakan untuk memverifikasi konfigurasi, memeriksa file pengaturan mana hook berasal, atau memeriksa perintah, prompt, atau URL hook.
Menu menampilkan semua lima tipe hook: command, prompt, agent, http, dan mcp_tool. Setiap hook diberi label dengan awalan [type] dan sumber menunjukkan di mana itu didefinisikan:
User: dari~/.claude/settings.jsonProject: dari.claude/settings.jsonLocal: dari.claude/settings.local.jsonPlugin: darihooks/hooks.jsonpluginSession: terdaftar dalam memori untuk sesi saat iniBuilt-in: terdaftar secara internal oleh Claude Code
Nonaktifkan atau hapus hooks
Untuk menghapus hook, hapus entrinya dari file JSON pengaturan. Untuk menonaktifkan semua hooks sementara tanpa menghapusnya, atur"disableAllHooks": true dalam file pengaturan Anda. Tidak ada cara untuk menonaktifkan hook individual sambil menyimpannya dalam konfigurasi.
Pengaturan disableAllHooks menghormati hierarki pengaturan terkelola. Jika administrator telah mengonfigurasi hooks melalui pengaturan kebijakan terkelola, disableAllHooks yang diatur dalam pengaturan pengguna, proyek, atau lokal tidak dapat menonaktifkan hooks terkelola tersebut. Hanya disableAllHooks yang diatur pada tingkat pengaturan terkelola yang dapat menonaktifkan hooks terkelola.
Pengeditan langsung ke hooks dalam file pengaturan biasanya diambil secara otomatis oleh file watcher.
Input dan output hook
Command hooks menerima data JSON melalui stdin dan mengkomunikasikan hasil melalui kode keluar, stdout, dan stderr. HTTP hooks menerima JSON yang sama sebagai badan permintaan POST dan mengkomunikasikan hasil melalui badan respons HTTP. Bagian ini mencakup bidang dan perilaku yang umum untuk semua events. Setiap bagian event di bawah Hook events mencakup skema input spesifiknya dan opsi kontrol keputusan. Pada macOS dan Linux, command hooks berjalan dalam sesi mereka sendiri tanpa terminal pengontrol sejak v2.1.139. Proses hook dan proses anak apa pun tidak dapat membuka/dev/tty atau mengirim urutan escape langsung ke antarmuka Claude Code. Windows tidak memiliki /dev/tty. Untuk menampilkan pesan kepada pengguna di platform apa pun, kembalikan systemMessage dalam output JSON. Untuk memicu notifikasi desktop, atur judul jendela, atau bunyikan bel, kembalikan terminalSequence sebagai gantinya.
Bidang input umum
Hook events menerima bidang-bidang ini sebagai JSON, selain bidang spesifik event yang didokumentasikan dalam setiap bagian hook event. Untuk command hooks, JSON ini tiba melalui stdin. Untuk HTTP hooks, itu tiba sebagai badan permintaan POST.
Saat berjalan dengan
--agent atau di dalam subagent, dua bidang tambahan disertakan:
Hanya hooks
SessionStart yang dapat menerima bidang model, dan tidak dijamin ada. Tidak ada variabel lingkungan $CLAUDE_MODEL. Proses hook mewarisi lingkungan induk, jadi dapat membaca $ANTHROPIC_MODEL jika Anda menetapkannya di shell Anda, tetapi nilai itu tidak berubah ketika Anda beralih model dengan /model selama sesi. Satu set variabel tidak diwariskan: Claude Code menghapus variabel exporter OTEL_* dari setiap subprocess yang dijalankannya, termasuk hooks.
Misalnya, hook PreToolUse untuk perintah Bash menerima ini di stdin:
tool_name dan tool_input spesifik untuk event. Setiap bagian hook event mendokumentasikan bidang tambahan untuk event itu.
Output kode keluar
Kode keluar dari perintah hook Anda memberitahu Claude Code apakah tindakan harus dilanjutkan, diblokir, atau diabaikan. Exit 0 berarti sukses. Claude Code mengurai stdout untuk bidang output JSON. Output JSON hanya diproses pada exit 0. Untuk sebagian besar events, stdout ditulis ke debug log tetapi tidak ditampilkan dalam transkrip. Pengecualiannya adalahUserPromptSubmit, UserPromptExpansion, dan SessionStart, di mana stdout ditambahkan sebagai konteks yang dapat dilihat dan ditindaklanjuti Claude.
Exit 2 berarti kesalahan blocking. Claude Code mengabaikan stdout dan JSON apa pun di dalamnya. Sebagai gantinya, teks stderr diumpankan kembali ke Claude sebagai pesan kesalahan. Efeknya tergantung pada event: PreToolUse memblokir pemanggilan tool, UserPromptSubmit menolak prompt, dan sebagainya. Lihat perilaku kode keluar 2 untuk daftar lengkap.
Kode keluar lainnya adalah kesalahan non-blocking untuk sebagian besar hook events. Transkrip menampilkan pemberitahuan <hook name> hook error diikuti oleh baris pertama stderr, jadi Anda dapat mengidentifikasi penyebabnya tanpa --debug. Eksekusi berlanjut dan stderr lengkap ditulis ke debug log.
Misalnya, skrip perintah hook yang memblokir perintah Bash berbahaya:
Perilaku kode keluar 2 per event
Kode keluar 2 adalah cara hook menandakan “berhenti, jangan lakukan ini.” Efeknya tergantung pada event, karena beberapa event mewakili tindakan yang dapat diblokir (seperti pemanggilan tool yang belum terjadi) dan yang lain mewakili hal-hal yang sudah terjadi atau tidak dapat dicegah.
Untuk
SessionStart, Setup, dan SubagentStart, stderr kode keluar 2 dirender dalam transkrip sebagai pemberitahuan <hook name> hook error, dengan cara yang sama seperti kesalahan non-blocking. Claude tidak melihatnya, dan sesi atau subagent berlanjut. Untuk SubagentStart, pemberitahuan muncul dalam transkrip subagent itu sendiri, bukan dalam percakapan induk.
Sejak Claude Code v2.1.199, SessionStart, Setup, dan SubagentStart menampilkan stderr kode keluar 2 dalam transkrip. Versi sebelumnya menulisnya ke debug log saja.
Penanganan respons HTTP
HTTP hooks menggunakan kode status HTTP dan badan respons sebagai pengganti kode keluar dan stdout:- 2xx dengan badan kosong: sukses, setara dengan kode keluar 0 tanpa output
- 2xx dengan badan teks biasa: sukses, teks ditambahkan sebagai konteks
- 2xx dengan badan JSON: sukses, diurai menggunakan skema JSON output yang sama seperti command hooks
- Status non-2xx: kesalahan non-blocking, eksekusi berlanjut
- Kegagalan koneksi atau timeout: kesalahan non-blocking, eksekusi berlanjut
Output JSON
Kode keluar memungkinkan Anda memblokir atau tetap diam, tetapi output JSON memberikan kontrol yang lebih halus. Alih-alih keluar dengan kode 2 untuk memblokir, keluar 0 dan cetak objek JSON ke stdout. Claude Code membaca bidang tertentu dari JSON itu untuk mengontrol perilaku, termasuk decision control untuk memblokir, mengizinkan, atau meningkatkan ke pengguna.Anda harus memilih satu pendekatan per hook, bukan keduanya: gunakan kode keluar saja untuk signaling, atau keluar 0 dan cetak JSON untuk kontrol terstruktur. Claude Code hanya memproses JSON pada exit 0. Jika Anda keluar 2, JSON apa pun diabaikan.
additionalContext, systemMessage, dan plain stdout, dibatasi pada 10.000 karakter. Output yang melebihi batas ini disimpan ke file dan diganti dengan pratinjau dan path file, dengan cara yang sama seperti hasil tool besar ditangani.
Objek JSON mendukung tiga jenis bidang:
- Bidang universal seperti
continuebekerja di semua events. Ini tercantum dalam tabel di bawah. - Top-level
decisiondanreasondigunakan oleh beberapa events untuk memblokir atau memberikan umpan balik. hookSpecificOutputadalah objek bersarang untuk events yang memerlukan kontrol yang lebih kaya. Ini memerlukan bidanghookEventNameyang diatur ke nama event.
Untuk menghentikan Claude sepenuhnya terlepas dari tipe event:
Emit terminal notifications
BidangterminalSequence memerlukan Claude Code v2.1.141 atau lebih baru.
Hooks berjalan tanpa terminal pengontrol, jadi menulis urutan escape langsung ke /dev/tty gagal. Sebagai gantinya, kembalikan urutan escape dalam bidang terminalSequence dan Claude Code memancarkannya untuk Anda melalui jalur penulisan terminal miliknya sendiri. Ini bebas race, bekerja di dalam tmux dan GNU screen, dan bekerja di Windows di mana tidak ada /dev/tty.
Bidang menerima string dari satu atau lebih urutan escape yang diizinkan:
- OSC
0,1,2: judul jendela dan ikon - OSC
9: notifikasi iTerm2, ConEmu, Windows Terminal, dan WezTerm, termasuk9;4kemajuan taskbar - OSC
99: notifikasi Kitty - OSC
777: notifikasi urxvt, Ghostty, dan Warp - BEL telanjang
Notification. Urutan escape dibangun dengan printf octal escapes sehingga byte kontrol tidak pernah muncul di baris perintah shell, dan jq -n --arg membangun output JSON sehingga tanda kutip, backslash, dan newline dalam pesan notifikasi diloloskan dengan benar:
{ "terminalSequence": "..." } sama dari shell atau bahasa apa pun. Di Windows, bangun string escape di PowerShell atau skrip dan pancarkan objek JSON yang sama.
terminalSequence adalah pengganti yang didukung untuk hooks yang sebelumnya menulis urutan escape langsung ke /dev/tty. Daftar putih dibatasi pada urutan yang tidak dapat memindahkan kursor atau mengubah warna, jadi hook tidak pernah dapat merusak prompt di layar.Tambahkan konteks untuk Claude
BidangadditionalContext meneruskan string dari hook Anda ke jendela konteks Claude. Claude Code membungkus string dalam pengingat sistem dan menyisipkannya ke dalam percakapan pada titik di mana hook dijalankan. Claude membaca pengingat pada permintaan model berikutnya, tetapi itu tidak muncul sebagai pesan chat dalam antarmuka.
Kembalikan additionalContext di dalam hookSpecificOutput bersama nama event:
- SessionStart, Setup, dan SubagentStart: di awal percakapan, sebelum prompt pertama
- UserPromptSubmit dan UserPromptExpansion: bersama prompt yang dikirimkan
- PreToolUse, PostToolUse, PostToolUseFailure, dan PostToolBatch: di sebelah hasil tool
- Stop dan SubagentStop: di akhir giliran. Percakapan berlanjut sehingga Claude dapat bertindak atas umpan balik. Lihat Stop decision control
additionalContext untuk event yang sama, Claude menerima semua nilai. Jika nilai melebihi 10.000 karakter, Claude Code menulis teks lengkap ke file di direktori sesi dan meneruskan Claude path file dengan pratinjau singkat sebagai gantinya.
Gunakan additionalContext untuk informasi yang harus diketahui Claude tentang keadaan saat ini lingkungan Anda atau operasi yang baru saja dijalankan:
- Keadaan lingkungan: branch saat ini, target deployment, atau flag fitur aktif
- Aturan proyek bersyarat: perintah test mana yang berlaku untuk file yang baru diedit, direktori mana yang read-only di worktree ini
- Data eksternal: masalah terbuka yang ditugaskan kepada Anda, hasil CI terbaru, konten yang diambil dari layanan internal
bun test” dibaca sebagai informasi proyek. Teks yang dibingkai sebagai perintah sistem out-of-band dapat memicu pertahanan injeksi prompt Claude, yang menyebabkan Claude menampilkan teks kepada Anda alih-alih memperlakukannya sebagai konteks.
Setelah disuntikkan, teks disimpan dalam transkrip sesi. Untuk events mid-session seperti PostToolUse atau UserPromptSubmit, melanjutkan dengan --continue atau --resume memutar ulang teks yang disimpan daripada menjalankan kembali hook untuk giliran masa lalu, jadi nilai seperti timestamp atau commit SHA menjadi usang pada resume. Hook SessionStart dijalankan lagi pada resume dengan source diatur ke "resume", jadi mereka dapat menyegarkan konteks mereka.
Kontrol keputusan
Tidak setiap event mendukung pemblokiran atau kontrol perilaku melalui JSON. Events yang melakukannya masing-masing menggunakan set bidang yang berbeda untuk mengekspresikan keputusan itu. Gunakan tabel ini sebagai referensi cepat sebelum menulis hook:
Beberapa events juga dapat menulis ulang konten daripada hanya mengizinkan atau memblokir:
PreToolUse:updatedInputlangsung di bawahhookSpecificOutputmenggantikan argumen tool sebelum dijalankan. Lihat PreToolUse decision control untuk set lengkap opsi.PermissionRequest:updatedInputdi dalam objekdecision. Lihat PermissionRequest decision control untuk set lengkap opsi.PostToolUse:updatedToolOutputmenggantikan hasil tool. Lihat PostToolUse decision control untuk set lengkap opsi.UserPromptSubmit: tidak dapat mengganti prompt; hanya menyuntikkanadditionalContextdi sampingnya
PreToolUse untuk input tool keluar dan PostToolUse untuk hasil tool masuk.
Berikut adalah contoh setiap pola dalam aksi:
- Top-level decision
- PreToolUse
- PermissionRequest
Digunakan oleh
UserPromptSubmit, UserPromptExpansion, PostToolUse, PostToolUseFailure, PostToolBatch, Stop, SubagentStop, ConfigChange, dan PreCompact. Satu-satunya nilai adalah "block". Untuk mengizinkan tindakan dilanjutkan, hilangkan decision dari JSON Anda, atau keluar 0 tanpa JSON apa pun:Hook events
Setiap event sesuai dengan titik dalam siklus hidup Claude Code di mana hooks dapat dijalankan. Bagian-bagian di bawah diurutkan untuk mencocokkan siklus hidup: dari pengaturan sesi melalui loop agentic ke akhir sesi. Setiap bagian menjelaskan kapan event dijalankan, matcher apa yang didukungnya, JSON input yang diterima, dan cara mengontrol perilaku melalui output.SessionStart
Dijalankan ketika Claude Code memulai sesi baru atau melanjutkan sesi yang ada. Berguna untuk memuat konteks pengembangan seperti masalah yang ada atau perubahan terbaru pada codebase Anda, atau menyiapkan variabel lingkungan. Untuk konteks statis yang tidak memerlukan skrip, gunakan CLAUDE.md sebagai gantinya. SessionStart dijalankan pada setiap sesi, jadi jaga hooks ini tetap cepat. Hanya hookstype: "command" dan type: "mcp_tool" yang didukung.
Nilai matcher sesuai dengan cara sesi dimulai:
SessionStart input
Selain bidang input umum, SessionStart hooks menerimasource dan secara opsional model, agent_type, dan session_title:
SessionStart decision control
Teks apa pun yang dicetak skrip hook ke stdout ditambahkan sebagai konteks untuk Claude. Selain bidang output JSON yang tersedia untuk semua hooks, Anda dapat mengembalikan bidang spesifik event ini:suppressOutput atau sessionTitle.
Gunakan reloadSkills ketika SessionStart hook menginstal atau memperbarui skills. Penemuan skill biasanya berjalan sebelum SessionStart hooks selesai, jadi file yang ditulis hook ke ~/.claude/skills/ atau .claude/skills/ tidak akan muncul sampai sesi berikutnya. Contoh ini menyinkronkan repositori skills bersama dan meminta pemindaian ulang:
Persist environment variables
SessionStart hooks memiliki akses ke variabel lingkunganCLAUDE_ENV_FILE, yang menyediakan path file di mana Anda dapat mempertahankan variabel lingkungan untuk perintah Bash berikutnya.
Untuk menetapkan variabel lingkungan individual, tulis pernyataan export ke CLAUDE_ENV_FILE. Gunakan append (>>) untuk mempertahankan variabel yang ditetapkan oleh hooks lain:
CLAUDE_ENV_FILE tersedia untuk SessionStart, Setup, CwdChanged, dan FileChanged hooks. Tipe hook lainnya tidak memiliki akses ke variabel ini.Setup
Dijalankan hanya ketika Anda meluncurkan Claude Code dengan--init-only, atau dengan --init atau --maintenance dalam mode non-interaktif dengan flag -p. Itu tidak dijalankan pada startup normal. Gunakan untuk instalasi dependensi satu kali atau pembersihan terjadwal yang Anda picu secara eksplisit dari CI atau skrip, terpisah dari startup sesi normal. Untuk inisialisasi per-sesi, gunakan SessionStart sebagai gantinya.
Nilai matcher sesuai dengan flag CLI yang memicu hook:
--init-only menjalankan Setup hooks dan SessionStart hooks dengan matcher startup, kemudian keluar tanpa memulai percakapan. --init dan --maintenance menjalankan Setup hooks hanya ketika digabungkan dengan -p; dalam sesi interaktif dua flag itu saat ini tidak menjalankan Setup hooks.
Karena Setup tidak dijalankan pada setiap peluncuran, plugin yang memerlukan dependensi yang diinstal tidak dapat mengandalkan Setup saja. Pola praktis adalah memeriksa dependensi pada penggunaan pertama dan menginstal jika tidak ada, misalnya hook atau skill yang menguji ${CLAUDE_PLUGIN_DATA}/node_modules dan menjalankan npm install jika tidak ada. Lihat direktori data persisten untuk tempat menyimpan dependensi yang diinstal.
Setup input
Selain bidang input umum, Setup hooks menerima bidangtrigger yang diatur ke "init" atau "maintenance":
Setup decision control
Setup hooks tidak dapat memblokir. Kode keluar non-nol apa pun, termasuk 2, menampilkan stderr ke pengguna sebagai pemberitahuan<hook name> hook error, dan eksekusi berlanjut. Dalam mode non-interaktif, output hook muncul hanya ketika Anda meluncurkan dengan --verbose.
Untuk meneruskan informasi ke konteks Claude, kembalikan additionalContext dalam output JSON; plain stdout ditulis ke debug log saja. Selain bidang output JSON yang tersedia untuk semua hooks, Anda dapat mengembalikan bidang spesifik event ini:
CLAUDE_ENV_FILE. Variabel yang ditulis ke file itu bertahan ke perintah Bash berikutnya untuk sesi, sama seperti dalam SessionStart hooks. Hanya hooks type: "command" dan type: "mcp_tool" yang didukung.
InstructionsLoaded
Dijalankan ketika fileCLAUDE.md atau .claude/rules/*.md dimuat ke dalam konteks. Event ini dijalankan saat startup sesi untuk file yang dimuat dengan eager dan lagi nanti ketika file dimuat dengan lazy, misalnya ketika Claude mengakses subdirektori yang berisi CLAUDE.md bersarang atau ketika aturan bersyarat dengan frontmatter paths: cocok. Hook tidak mendukung pemblokiran atau kontrol keputusan. Itu dijalankan secara asinkron untuk tujuan observabilitas.
Matcher dijalankan terhadap load_reason. Misalnya, gunakan "matcher": "session_start" untuk dijalankan hanya untuk file yang dimuat saat startup sesi, atau "matcher": "path_glob_match|nested_traversal" untuk dijalankan hanya untuk lazy loads.
InstructionsLoaded input
Selain bidang input umum, InstructionsLoaded hooks menerima bidang-bidang ini:InstructionsLoaded decision control
InstructionsLoaded hooks tidak memiliki kontrol keputusan. Mereka tidak dapat memblokir atau memodifikasi pemuatan instruksi. Gunakan event ini untuk audit logging, compliance tracking, atau observabilitas.UserPromptSubmit
Dijalankan ketika pengguna mengirimkan prompt, sebelum Claude memproses. Ini memungkinkan Anda menambahkan konteks tambahan berdasarkan prompt/percakapan, memvalidasi prompts, atau memblokir jenis prompts tertentu. HooksUserPromptSubmit memiliki timeout default 30 detik untuk tipe command, http, dan mcp_tool, lebih pendek dari default 600 detik untuk tipe tersebut pada event lain. Karena hook ini dijalankan sebelum setiap prompt dan memblokir pemrosesan model sampai selesai, hook yang macet menghentikan sesi. Jika hook Anda memerlukan lebih banyak waktu, atur bidang timeout dalam entri hook.
Hook UserPromptSubmit command, HTTP, atau MCP tool yang mencapai timeout-nya dibatalkan dan output-nya, termasuk additionalContext apa pun, dibuang. Prompt masih mencapai Claude tanpa konteks itu. Mulai dari v2.1.196, transkrip menampilkan pemberitahuan yang menamai hook, timeout yang dijalankan, dan bahwa output dibuang. Versi sebelumnya membatalkan hook tanpa pemberitahuan.
Hook callback Agent SDK pada UserPromptSubmit yang mencapai timeout-nya memblokir prompt dengan pesan yang menamai hook dan timeout, karena callback di sana dapat bertindak sebagai policy gate yang tidak boleh gagal terbuka. Sesi berlanjut. Sebelum v2.1.208, timeout callback pada event itu mengakhiri giliran dengan kesalahan eksekusi.
UserPromptSubmit input
Selain bidang input umum, UserPromptSubmit hooks menerima bidangprompt yang berisi teks yang dikirimkan pengguna.
UserPromptSubmit decision control
HooksUserPromptSubmit dapat mengontrol apakah prompt pengguna diproses dan menambahkan konteks. Semua bidang output JSON tersedia.
Ada dua cara untuk menambahkan konteks ke percakapan pada kode keluar 0:
- Plain text stdout: teks non-JSON apa pun yang ditulis ke stdout ditambahkan sebagai konteks
- JSON dengan
additionalContext: gunakan format JSON di bawah untuk kontrol lebih. BidangadditionalContextditambahkan sebagai konteks
additionalContext disuntikkan sebagai pengingat sistem yang dibaca Claude tanpa entri transkrip yang terlihat.
Untuk memblokir prompt, kembalikan objek JSON dengan decision diatur ke "block":
UserPromptExpansion
Dijalankan ketika perintah slash yang diketik pengguna berkembang menjadi prompt sebelum mencapai Claude. Gunakan ini untuk memblokir perintah tertentu dari invokasi langsung, menyuntikkan konteks untuk skill tertentu, atau mencatat perintah mana yang diinvokasi pengguna. Misalnya, hook yang cocok dengandeploy dapat memblokir /deploy kecuali file persetujuan ada, atau hook yang cocok dengan skill review dapat menambahkan checklist review tim sebagai additionalContext.
Event ini mencakup path yang PreToolUse tidak: hook PreToolUse yang cocok dengan tool Skill hanya dijalankan ketika Claude memanggil tool, tetapi mengetik /skillname secara langsung melewati PreToolUse. UserPromptExpansion dijalankan pada path langsung itu.
Cocok pada command_name. Biarkan matcher kosong untuk dijalankan pada setiap slash command prompt-type.
UserPromptExpansion input
Selain bidang input umum, UserPromptExpansion hooks menerimaexpansion_type, command_name, command_args, command_source, dan string prompt asli. Bidang expansion_type adalah slash_command untuk skill dan custom commands, atau mcp_prompt untuk MCP server prompts.
UserPromptExpansion decision control
HooksUserPromptExpansion dapat memblokir ekspansi atau menambahkan konteks. Semua bidang output JSON tersedia.
MessageDisplay
Dijalankan saat pesan asisten mengalir ke layar. Claude Code menampilkan pesan dalam kenaikan: setiap kali batch baris yang baru selesai siap untuk dirender, hook dijalankan sekali dengan baris-baris itu dan Claude Code merender teks pengganti hook di tempatnya. Pesan panjang menghasilkan beberapa panggilan; pesan pendek mungkin hanya menghasilkan satu. Gunakan MessageDisplay untuk:- menghapus markdown untuk tampilan minimal
- mengubah teks yang ditampilkan aplikasi Agent SDK kepada penggunanya
- menyensor API keys atau hostname internal dari respons Claude
timeout dalam entri hook.
MessageDisplay hanya untuk tampilan: teks pengganti hanya mengubah apa yang dirender di layar. Transkrip dan apa yang dilihat Claude menyimpan teks asli, jadi Claude tidak pernah melihat pengganti, dan mode verbose menampilkan asli. Hook menerima teks pesan asisten saja, jadi hasil tool dan teks yang Anda ketik dirender tanpa perubahan.
MessageDisplay tidak mendukung matchers dan dijalankan untuk setiap pesan asisten yang mengalir teks; pesan tanpa teks, seperti respons hanya pemanggilan tool, tidak memicunya.
Dalam run non-interaktif, termasuk kueri Agent SDK dan claude -p, MessageDisplay dijalankan sekali per pesan asisten alih-alih sekali per batch baris. Panggilan tunggal tiba setelah pesan selesai dan membawa teks pesan lengkap: index adalah 0, final adalah true, dan delta menyimpan seluruh pesan. Hook yang mengumpulkan teks delta untuk setiap pesan menerima teks total yang sama dalam kedua mode.
MessageDisplay input
Selain bidang input umum, MessageDisplay hooks menerima pengenal untuk giliran dan pesan, posisi panggilan ini dalam pesan, dan teks baru dalamdelta. Batas batch tergantung pada bagaimana teks mengalir, jadi gunakan index dan final untuk melacak kemajuan melalui pesan daripada mengharapkan baris dikelompokkan dengan cara tertentu.
MessageDisplay output
Selain bidang output JSON yang tersedia untuk semua hooks, MessageDisplay hooks dapat mengembalikandisplayContent untuk mengganti delta di layar:
MessageDisplay hooks tidak memiliki kontrol keputusan. Mereka tidak dapat memblokir pesan atau mengubah apa yang disimpan dalam transkrip atau dikirim ke Claude.
Contoh ini menghapus pemformatan markdown dari respons Claude untuk tampilan teks biasa. Skrip membaca setiap batch dari stdin, menghapus penanda bold dan backtick kode inline dari
delta, dan mengembalikan hasilnya sebagai displayContent.
- macOS/Linux
- Windows (PowerShell)
Daftarkan command hook untuk event dalam file pengaturan Anda:Simpan skrip ini ke Skrip memerlukan
.claude/hooks/plain-display.sh dalam proyek Anda dan buat dapat dieksekusi dengan chmod +x:jq di PATH Anda.jq hilang, Claude Code menampilkan teks asli dan mencatat kegagalan hanya dalam output debug, bukan dalam sesi.
PreToolUse
Dijalankan setelah Claude membuat parameter tool dan sebelum memproses pemanggilan tool. Cocok pada nama tool:Bash, Edit, Write, Read, Glob, Grep, Agent, WebFetch, WebSearch, AskUserQuestion, ExitPlanMode, dan nama MCP tool apa pun.
Gunakan PreToolUse decision control untuk mengizinkan, menolak, menanyakan, atau menunda pemanggilan tool.
PreToolUse input
Selain bidang input umum, PreToolUse hooks menerimatool_name, tool_input, dan tool_use_id. Bidang tool_input tergantung pada tool:
Menjalankan perintah shell.
Membuat atau menimpa file.
Mengganti string dalam file yang ada.
Membaca konten file.
Menemukan file yang cocok dengan pola glob.
Mencari konten file dengan ekspresi reguler.
Mengambil dan memproses konten web.
Mencari web.
Spawn subagent.
Dalam
PostToolUse, tool_response untuk panggilan Agent yang selesai membawa teks akhir subagent bersama dengan telemetri penggunaan. Baca bidang-bidang ini untuk mencatat biaya per-subagent dari hook:
Untuk background subagents, tool mengembalikan segera setelah meluncurkan, jadi
tool_response tidak membawa bidang penggunaan. Itu memiliki status: "async_launched", agentId, description, prompt, outputFile, dan resolvedModel.
Bidang resolvedModel menamai model yang sebenarnya dijalankan subagent, yang dapat berbeda dari nilai model dalam tool_input. Itu memerlukan Claude Code v2.1.174 atau lebih baru.
Mengajukan pertanyaan multiple-choice satu hingga empat kepada pengguna.
Menyajikan rencana dan meminta pengguna untuk menyetujuinya sebelum Claude meninggalkan plan mode. Claude menulis rencana ke file di disk sebelum memanggil tool, jadi
tool_input literal dari model hanya membawa allowedPrompts. Claude Code menyuntikkan konten rencana dan path file sebelum meneruskan input ke hooks.
Dalam
PostToolUse, tool_response adalah objek dengan bidang plan dan filePath yang menyimpan rencana yang disetujui, ditambah flag status internal. Baca tool_response.plan untuk konten rencana daripada membaca ulang file dari disk.
PreToolUse decision control
HooksPreToolUse dapat mengontrol apakah pemanggilan tool dilanjutkan. Tidak seperti hooks lain yang menggunakan bidang decision tingkat atas, PreToolUse mengembalikan keputusannya di dalam objek hookSpecificOutput. Ini memberikannya kontrol yang lebih kaya: empat hasil (izinkan, tolak, tanya, atau tunda) ditambah kemampuan untuk memodifikasi input tool sebelum eksekusi.
Ketika beberapa PreToolUse hooks mengembalikan keputusan berbeda, prioritas adalah
deny > defer > ask > allow.
Ketika hook mengembalikan "ask", dialog izin yang ditampilkan kepada pengguna mencakup label yang mengidentifikasi dari mana hook berasal: misalnya, [User], [Project], [Plugin], atau [Local]. Ini membantu pengguna memahami sumber konfigurasi mana yang meminta konfirmasi.
AskUserQuestion dan ExitPlanMode memerlukan interaksi pengguna dan biasanya memblokir dalam mode non-interaktif dengan flag -p. Mengembalikan permissionDecision: "allow" bersama dengan updatedInput memenuhi persyaratan itu: hook membaca input tool dari stdin, mengumpulkan jawaban melalui UI Anda sendiri, dan mengembalikannya dalam updatedInput sehingga tool dijalankan tanpa meminta. Mengembalikan "allow" saja tidak cukup untuk tools ini. Untuk AskUserQuestion, kembalikan array questions asli dan tambahkan objek answers yang memetakan teks setiap pertanyaan ke jawaban yang dipilih.
Connector tools organisasi Anda atur ke ask meminta bahkan ketika hook mengembalikan "allow".
Mulai dari v2.1.199, tool MCP yang server-nya menandainya dengan _meta["anthropic/requiresUserInteraction"] lebih ketat: hook tidak dapat melewati prompt persetujuannya dengan "allow", dengan atau tanpa updatedInput, karena Claude Code tidak dapat mengkonfirmasi hook mengumpulkan interaksi yang dibutuhkan tool.
PreToolUse sebelumnya menggunakan bidang
decision dan reason tingkat atas, tetapi ini sudah usang untuk event ini. Gunakan hookSpecificOutput.permissionDecision dan hookSpecificOutput.permissionDecisionReason sebagai gantinya. Nilai usang "approve" dan "block" memetakan ke "allow" dan "deny" masing-masing. Events lain seperti PostToolUse dan Stop terus menggunakan decision dan reason tingkat atas sebagai format saat ini mereka.Defer a tool call for later
"defer" adalah untuk integrasi yang menjalankan claude -p sebagai subprocess dan membaca output JSON-nya, seperti aplikasi Agent SDK atau UI kustom yang dibangun di atas Claude Code. Ini memungkinkan proses pemanggil itu menjeda Claude pada pemanggilan tool, mengumpulkan input melalui antarmuka miliknya sendiri, dan melanjutkan di mana ia berhenti. Claude Code menghormati nilai ini hanya dalam mode non-interaktif dengan flag -p. Dalam sesi interaktif itu mencatat peringatan dan mengabaikan hasil hook.
Tool AskUserQuestion adalah kasus tipikal: Claude ingin menanyakan sesuatu kepada pengguna, tetapi tidak ada terminal untuk menjawab. Perjalanan bolak-balik bekerja seperti ini:
- Claude memanggil
AskUserQuestion. HookPreToolUsedijalankan. - Hook mengembalikan
permissionDecision: "defer". Tool tidak dijalankan. Proses keluar denganstop_reason: "tool_deferred"dan pemanggilan tool yang tertunda dipertahankan dalam transkrip. - Proses pemanggil membaca
deferred_tool_usedari hasil SDK, menampilkan pertanyaan di UI miliknya sendiri, dan menunggu jawaban. - Proses pemanggil menjalankan
claude -p --resume <session-id>. Pemanggilan tool yang sama menjalankanPreToolUselagi. - Hook mengembalikan
permissionDecision: "allow"dengan jawaban dalamupdatedInput. Tool dijalankan dan Claude melanjutkan.
deferred_tool_use membawa id, name, dan input tool. input adalah parameter yang Claude hasilkan untuk pemanggilan tool, ditangkap sebelum eksekusi:
cleanupPeriodDays yang menghapus file sesi setelah 30 hari secara default. Jika jawaban tidak siap saat Anda melanjutkan, hook dapat mengembalikan "defer" lagi dan proses keluar dengan cara yang sama. Proses pemanggil mengontrol kapan harus memecah loop dengan akhirnya mengembalikan "allow" atau "deny" dari hook.
"defer" hanya bekerja ketika Claude membuat satu pemanggilan tool dalam giliran. Jika Claude membuat beberapa pemanggilan tool sekaligus, "defer" diabaikan dengan peringatan dan tool melanjutkan melalui alur izin normal. Batasan ada karena resume hanya dapat menjalankan kembali satu tool: tidak ada cara untuk menunda satu pemanggilan dari batch tanpa meninggalkan yang lain tidak terselesaikan.
Jika tool yang ditunda tidak lagi tersedia saat Anda melanjutkan, proses keluar dengan stop_reason: "tool_deferred_unavailable" dan is_error: true sebelum hook dijalankan. Ini terjadi ketika server MCP yang menyediakan tool tidak terhubung untuk sesi yang dilanjutkan. Payload deferred_tool_use masih disertakan sehingga Anda dapat mengidentifikasi tool mana yang hilang.
--resume memulihkan mode izin yang aktif saat tool ditunda, jadi Anda tidak perlu meneruskan --permission-mode lagi. Pengecualiannya adalah plan dan bypassPermissions, yang tidak pernah dibawa. Meneruskan --permission-mode secara eksplisit pada resume menimpa nilai yang dipulihkan.PermissionRequest
Dijalankan ketika pengguna ditampilkan dialog izin. Gunakan PermissionRequest decision control untuk mengizinkan atau menolak atas nama pengguna. Cocok pada nama tool, nilai yang sama seperti PreToolUse.PermissionRequest input
PermissionRequest hooks menerima bidangtool_name dan tool_input seperti PreToolUse hooks, tetapi tanpa tool_use_id. Array permission_suggestions opsional berisi opsi “selalu izinkan” yang biasanya dilihat pengguna dalam dialog izin. Perbedaannya adalah kapan hook dijalankan: PermissionRequest hooks dijalankan ketika dialog izin akan ditampilkan ke pengguna, sementara PreToolUse hooks dijalankan sebelum eksekusi tool terlepas dari status izin.
PermissionRequest decision control
HooksPermissionRequest dapat mengizinkan atau menolak permintaan izin. Selain bidang output JSON yang tersedia untuk semua hooks, skrip hook Anda dapat mengembalikan objek decision dengan bidang spesifik event ini:
Permission update entries
Bidang outputupdatedPermissions dan bidang input permission_suggestions keduanya menggunakan array objek entry yang sama. Setiap entry memiliki type yang menentukan bidang lainnya, dan destination yang mengontrol di mana perubahan ditulis.
setMode dengan bypassPermissions hanya berlaku jika sesi diluncurkan dengan mode bypass sudah tersedia: --dangerously-skip-permissions, --permission-mode bypassPermissions, --allow-dangerously-skip-permissions, atau permissions.defaultMode: "bypassPermissions" dalam pengaturan, dan mode tidak dinonaktifkan oleh permissions.disableBypassPermissionsMode. Jika tidak, update adalah no-op. bypassPermissions tidak pernah dipertahankan sebagai defaultMode terlepas dari destination.destination pada setiap entry menentukan apakah perubahan tetap dalam memori atau persisten ke file pengaturan.
Hook dapat mengembalikan salah satu dari
permission_suggestions yang diterima sebagai output updatedPermissions miliknya sendiri, yang setara dengan pengguna memilih opsi “selalu izinkan” itu dalam dialog.
PostToolUse
Dijalankan segera setelah tool selesai dengan sukses. Cocok pada nama tool, nilai yang sama seperti PreToolUse.PostToolUse input
HooksPostToolUse dijalankan setelah tool sudah dijalankan dengan sukses. Input mencakup tool_input, argumen yang dikirim ke tool, dan tool_response, hasil yang dikembalikan. Skema yang tepat untuk keduanya tergantung pada tool.
PostToolUse decision control
HooksPostToolUse dapat memberikan umpan balik ke Claude setelah eksekusi tool. Selain bidang output JSON yang tersedia untuk semua hooks, skrip hook Anda dapat mengembalikan bidang spesifik event ini:
Contoh di bawah mengganti output pemanggilan
Bash. Nilai pengganti cocok dengan bentuk output tool Bash:
PostToolUseFailure
Dijalankan ketika tool yang mulai dijalankan gagal: tool melempar kesalahan, atau tool MCP mengembalikan hasil kesalahan. Gunakan ini untuk mencatat kegagalan, mengirim alert, atau memberikan umpan balik korektif ke Claude. Cocok pada nama tool, nilai yang sama seperti PreToolUse.Event ini tidak dijalankan untuk pemanggilan tool yang ditolak sebelum eksekusi: nama tool yang tidak dikenal, input yang gagal validasi skema atau tool-spesifik, atau penolakan izin. Penolakan validasi dikembalikan sebagai hasil
tool_use_error dan terjadi sebelum hooks dijalankan, jadi mereka tidak menjalankan PreToolUse atau event ini. Penolakan izin menjalankan PreToolUse tetapi bukan event ini; lihat PermissionDenied.PostToolUseFailure input
PostToolUseFailure hooks menerima bidangtool_name dan tool_input yang sama seperti PostToolUse, bersama dengan informasi kesalahan sebagai bidang tingkat atas:
PostToolUseFailure decision control
HooksPostToolUseFailure dapat memberikan konteks ke Claude setelah kegagalan tool. Selain bidang output JSON yang tersedia untuk semua hooks, skrip hook Anda dapat mengembalikan bidang spesifik event ini:
PostToolBatch
Dijalankan sekali setelah setiap tool call dalam batch telah terselesaikan, sebelum Claude Code mengirimkan permintaan berikutnya ke model.PostToolUse dijalankan sekali per tool, yang berarti dijalankan secara bersamaan ketika Claude membuat pemanggilan tool paralel. PostToolBatch dijalankan tepat sekali dengan batch lengkap, jadi ini adalah tempat yang tepat untuk menyuntikkan konteks yang bergantung pada set tools yang dijalankan daripada pada tool tunggal. Tidak ada matcher untuk event ini.
PostToolBatch input
Selain bidang input umum, PostToolBatch hooks menerimatool_calls, array yang menjelaskan setiap pemanggilan tool dalam batch:
tool_response berisi konten yang sama yang diterima model dalam blok tool_result yang sesuai. Nilainya adalah string yang diserialisasi atau array blok konten, persis seperti yang dikeluarkan tool. Untuk Read, itu berarti teks dengan awalan nomor baris daripada konten file mentah. Respons dapat besar, jadi hanya parse bidang yang Anda butuhkan.
Bentuk
tool_response berbeda dari PostToolUse. PostToolUse meneruskan objek Output terstruktur tool, seperti {filePath: "...", success: true} untuk Write; PostToolBatch meneruskan konten tool_result yang diserialisasi yang dilihat model.PostToolBatch decision control
HooksPostToolBatch dapat menyuntikkan konteks untuk Claude. Selain bidang output JSON yang tersedia untuk semua hooks, skrip hook Anda dapat mengembalikan bidang spesifik event ini:
decision: "block" atau continue: false menghentikan loop agentic sebelum panggilan model berikutnya.
PermissionDenied
Dijalankan ketika pengklasifikasi mode otomatis menolak pemanggilan tool. Hook ini hanya dijalankan dalam mode otomatis: itu tidak dijalankan ketika Anda secara manual menolak dialog izin, ketika hookPreToolUse memblokir pemanggilan, atau ketika aturan deny cocok. Gunakan untuk mencatat penolakan pengklasifikasi, menyesuaikan konfigurasi, atau memberitahu model itu dapat mencoba lagi pemanggilan tool.
Cocok pada nama tool, nilai yang sama seperti PreToolUse.
PermissionDenied input
Selain bidang input umum, PermissionDenied hooks menerimatool_name, tool_input, tool_use_id, dan reason.
PermissionDenied decision control
PermissionDenied hooks dapat memberitahu model itu dapat mencoba lagi pemanggilan tool yang ditolak. Kembalikan objek JSON denganhookSpecificOutput.retry diatur ke true:
retry adalah true, Claude Code menambahkan pesan ke percakapan memberitahu model itu dapat mencoba lagi pemanggilan tool. Penolakan itu sendiri tidak dibatalkan. Jika hook Anda tidak mengembalikan JSON, atau mengembalikan retry: false, penolakan tetap dan model menerima pesan penolakan asli.
Notification
Dijalankan ketika Claude Code mengirimkan notifikasi. Cocok pada tipe notifikasi. Hilangkan matcher untuk menjalankan hooks untuk semua tipe notifikasi.
Tipe
agent_needs_input dan agent_completed memerlukan Claude Code v2.1.198 atau lebih baru.
Gunakan matchers terpisah untuk menjalankan handler berbeda tergantung pada tipe notifikasi. Konfigurasi ini memicu skrip alert khusus izin ketika Claude memerlukan persetujuan izin dan notifikasi berbeda ketika Claude telah idle:
Notification input
Selain bidang input umum, Notification hooks menerimamessage dengan teks notifikasi, title opsional, dan notification_type menunjukkan tipe mana yang dijalankan.
systemMessage berlaku.
SubagentStart
Dijalankan ketika subagent Claude Code dispawn melalui tool Agent. Mendukung matchers untuk memfilter berdasarkan nama tipe agent. Untuk agent bawaan, ini adalah nama agent sepertigeneral-purpose, Explore, atau Plan. Untuk custom subagents, ini adalah bidang name dari frontmatter agent, bukan nama file.
Untuk subagents yang dikirim oleh plugin, tipe agent adalah pengenal bersifat plugin seperti my-plugin:reviewer, bukan nama frontmatter biasa. Titik dua menempatkan nama bersifat plugin pada jalur ekspresi reguler, jadi jangkar matcher dengan ^ dan $ untuk kecocokan yang tepat: ^my-plugin:reviewer$.
SubagentStart input
Selain bidang input umum, SubagentStart hooks menerimaagent_id dengan pengenal unik untuk subagent dan agent_type dengan nama agent yang matcher filter.
SubagentStop
Dijalankan ketika subagent Claude Code telah selesai merespons. Cocok pada tipe agent, nilai yang sama seperti SubagentStart.SubagentStop input
Selain bidang input umum, SubagentStop hooks menerimastop_hook_active, agent_id, agent_type, agent_transcript_path, dan last_assistant_message. Bidang agent_type adalah nilai yang digunakan untuk pemfilteran matcher. transcript_path adalah transkrip sesi utama, sementara agent_transcript_path adalah transkrip subagent sendiri yang disimpan dalam folder subagents/ bersarang. Bidang last_assistant_message berisi konten teks respons akhir subagent, jadi hooks dapat mengaksesnya tanpa mengurai file transkrip.
SubagentStop hooks juga menerima array background_tasks dan session_crons yang dijelaskan di bawah Stop input, tersedia dalam Claude Code v2.1.145 atau lebih baru. Kedua array bersifat scoped ke sesi induk, bukan subagent.
hookSpecificOutput.additionalContext dengan hookEventName diatur ke "SubagentStop", untuk umpan balik non-error yang membuat subagent tetap berjalan. Mengembalikan decision: "block" dengan reason membuat subagent tetap berjalan dan mengirimkan reason ke subagent sebagai instruksi berikutnya. Untuk menyuntikkan konteks ke sesi induk setelah subagent kembali, gunakan hook PostToolUse pada tool Agent sebagai gantinya.
TaskCreated
Dijalankan ketika tugas sedang dibuat melalui toolTaskCreate. Gunakan ini untuk menegakkan konvensi penamaan, memerlukan deskripsi tugas, atau mencegah tugas tertentu dari dibuat.
Ketika hook TaskCreated keluar dengan kode 2, tugas tidak dibuat dan pesan stderr diumpankan kembali ke model sebagai umpan balik. Untuk menghentikan teammate sepenuhnya alih-alih menjalankannya kembali, kembalikan JSON dengan {"continue": false, "stopReason": "..."}. TaskCreated hooks tidak mendukung matchers dan dijalankan pada setiap kemunculan.
TaskCreated input
Selain bidang input umum, TaskCreated hooks menerimatask_id, task_subject, dan secara opsional task_description, teammate_name, dan team_name.
TaskCreated decision control
TaskCreated hooks mendukung dua cara untuk mengontrol pembuatan tugas:- Kode keluar 2: tugas tidak dibuat dan pesan stderr diumpankan kembali ke model sebagai umpan balik.
- JSON
{"continue": false, "stopReason": "..."}: menghentikan teammate sepenuhnya, mencocokkan perilaku hookStop.stopReasonditampilkan ke pengguna.
TaskCompleted
Dijalankan ketika tugas sedang ditandai sebagai selesai. Ini dijalankan dalam dua situasi: ketika agent apa pun secara eksplisit menandai tugas sebagai selesai melalui tool TaskUpdate, atau ketika agent team teammate menyelesaikan giliran dengan tugas yang sedang berlangsung. Gunakan ini untuk menegakkan kriteria penyelesaian seperti passing tests atau lint checks sebelum tugas dapat ditutup. Ketika hookTaskCompleted keluar dengan kode 2, tugas tidak ditandai sebagai selesai dan pesan stderr diumpankan kembali ke model sebagai umpan balik. Untuk menghentikan teammate sepenuhnya alih-alih menjalankannya kembali, kembalikan JSON dengan {"continue": false, "stopReason": "..."}. TaskCompleted hooks tidak mendukung matchers dan dijalankan pada setiap kemunculan.
TaskCompleted input
Selain bidang input umum, TaskCompleted hooks menerimatask_id, task_subject, dan secara opsional task_description, teammate_name, dan team_name.
TaskCompleted decision control
TaskCompleted hooks mendukung dua cara untuk mengontrol penyelesaian tugas:- Kode keluar 2: tugas tidak ditandai sebagai selesai dan pesan stderr diumpankan kembali ke model sebagai umpan balik.
- JSON
{"continue": false, "stopReason": "..."}: menghentikan teammate sepenuhnya, mencocokkan perilaku hookStop.stopReasonditampilkan ke pengguna.
Stop
Dijalankan ketika agent Claude Code utama telah selesai merespons. Tidak dijalankan jika penghentian terjadi karena interupsi pengguna. Kesalahan API menjalankan StopFailure sebagai gantinya.Stop input
Selain bidang input umum, Stop hooks menerimastop_hook_active, last_assistant_message, background_tasks, dan session_crons. Bidang stop_hook_active adalah true ketika Claude Code sudah melanjutkan sebagai hasil dari stop hook. Periksa nilai ini atau proses transkrip untuk menghindari memblokir pada kondisi yang tidak akan pernah terselesaikan. Claude Code menimpa hook dan mengakhiri giliran setelah 8 blok berturut-turut.
Bidang last_assistant_message berisi konten teks respons akhir Claude, jadi hooks dapat mengaksesnya tanpa mengurai file transkrip.
Array background_tasks dan session_crons, tersedia dalam Claude Code v2.1.145 atau lebih baru, memungkinkan hooks membedakan “sesi selesai” dari “sesi dijeda menunggu pekerjaan latar belakang untuk membangunkannya kembali”. Kedua array hadir ketika registri tugas dapat dijangkau dan kosong ketika tidak ada yang sedang berlangsung atau dijadwalkan.
Setiap entry dalam background_tasks menjelaskan satu tugas yang sedang berlangsung dan menggunakan bidang-bidang ini:
Setiap entry dalam
session_crons menjelaskan satu wakeup terjadwal yang bersifat sesi, bersumber dari CronCreate, ScheduleWakeup, dan /loop:
Contoh ini menunjukkan input Stop dengan satu tugas shell yang sedang berlangsung dan satu cron berulang:
Stop decision control
HooksStop dan SubagentStop dapat mengontrol apakah Claude melanjutkan. Selain bidang output JSON yang tersedia untuk semua hooks, skrip hook Anda dapat mengembalikan bidang spesifik event ini:
additionalContext ketika hook bekerja seperti yang dirancang dan memberikan panduan Claude, seperti “jalankan test suite sebelum selesai”. Ini membuat percakapan terus berlanjut melalui proteksi loop yang sama seperti decision: "block", yaitu input stop_hook_active dan batas 8-kontinuasi berturut-turut, tetapi transkrip memberi label Stop hook feedback dan tidak ada notifikasi kesalahan hook yang ditampilkan:
StopFailure
Dijalankan alih-alih Stop ketika giliran berakhir karena kesalahan API. Output dan kode keluar diabaikan. Gunakan ini untuk mencatat kegagalan, mengirim alert, atau mengambil tindakan pemulihan ketika Claude tidak dapat menyelesaikan respons karena rate limits, masalah autentikasi, atau kesalahan API lainnya.StopFailure input
Selain bidang input umum, StopFailure hooks menerimaerror, error_details opsional, dan last_assistant_message opsional. Bidang error mengidentifikasi tipe kesalahan dan digunakan untuk pemfilteran matcher.
TeammateIdle
Dijalankan ketika agent team teammate akan menjadi idle setelah menyelesaikan giliran. Gunakan ini untuk menegakkan quality gates sebelum teammate berhenti bekerja, seperti memerlukan passing lint checks atau memverifikasi bahwa file output ada. Ketika hookTeammateIdle keluar dengan kode 2, teammate menerima pesan stderr sebagai umpan balik dan terus bekerja alih-alih menjadi idle. Untuk menghentikan teammate sepenuhnya alih-alih menjalankannya kembali, kembalikan JSON dengan {"continue": false, "stopReason": "..."}. TeammateIdle hooks tidak mendukung matchers dan dijalankan pada setiap kemunculan.
TeammateIdle input
Selain bidang input umum, TeammateIdle hooks menerimateammate_name dan team_name.
TeammateIdle decision control
TeammateIdle hooks mendukung dua cara untuk mengontrol perilaku teammate:- Kode keluar 2: teammate menerima pesan stderr sebagai umpan balik dan terus bekerja alih-alih menjadi idle.
- JSON
{"continue": false, "stopReason": "..."}: menghentikan teammate sepenuhnya, mencocokkan perilaku hookStop.stopReasonditampilkan ke pengguna.
ConfigChange
Dijalankan ketika file konfigurasi berubah selama sesi. Gunakan ini untuk mengaudit perubahan pengaturan, menegakkan kebijakan keamanan, atau memblokir modifikasi tidak sah ke file konfigurasi. ConfigChange hooks dijalankan untuk perubahan ke file pengaturan, pengaturan kebijakan terkelola, dan file skill. Bidangsource dalam input memberitahu Anda tipe konfigurasi mana yang berubah, dan bidang file_path opsional menyediakan path ke file yang berubah.
Matcher memfilter pada sumber konfigurasi:
Contoh ini mencatat semua perubahan konfigurasi untuk audit keamanan:
ConfigChange input
Selain bidang input umum, ConfigChange hooks menerimasource dan secara opsional file_path. Bidang source menunjukkan tipe konfigurasi mana yang berubah, dan file_path menyediakan path ke file spesifik yang dimodifikasi.
ConfigChange decision control
ConfigChange hooks dapat memblokir perubahan konfigurasi dari berlaku. Gunakan kode keluar 2 atau JSONdecision untuk mencegah perubahan. Ketika diblokir, pengaturan baru tidak diterapkan ke sesi yang berjalan.
policy_settings tidak dapat diblokir. Hooks masih dijalankan untuk sumber policy_settings, jadi Anda dapat menggunakannya untuk audit logging, tetapi keputusan blocking apa pun diabaikan. Ini memastikan pengaturan yang dikelola enterprise selalu berlaku.
CwdChanged
Dijalankan ketika direktori kerja berubah selama sesi, misalnya ketika Claude menjalankan perintahcd. Gunakan ini untuk bereaksi terhadap perubahan direktori: muat ulang variabel lingkungan, aktifkan toolchains khusus proyek, atau jalankan skrip setup secara otomatis. Berpasangan dengan FileChanged untuk tools seperti direnv yang mengelola lingkungan per-direktori.
CwdChanged hooks memiliki akses ke CLAUDE_ENV_FILE. Variabel yang ditulis ke file itu bertahan ke perintah Bash berikutnya untuk sesi, sama seperti dalam SessionStart hooks.
CwdChanged tidak mendukung matchers dan dijalankan pada setiap perubahan direktori.
CwdChanged input
Selain bidang input umum, CwdChanged hooks menerimaold_cwd dan new_cwd.
CwdChanged output
Selain bidang output JSON yang tersedia untuk semua hooks, CwdChanged hooks dapat mengembalikanwatchPaths untuk secara dinamis menetapkan path file mana yang FileChanged pantau:
CwdChanged hooks tidak memiliki kontrol keputusan. Mereka tidak dapat memblokir perubahan direktori.
FileChanged
Dijalankan ketika file yang dipantau berubah di disk. Berguna untuk memuat ulang variabel lingkungan ketika file konfigurasi proyek dimodifikasi. Bidangmatcher untuk event ini melayani dua peran:
- Bangun daftar watch: nilai dibagi pada
|dan setiap segmen terdaftar sebagai nama file literal di direktori kerja, jadi".envrc|.env"menonton tepat dua file itu. Pola regex tidak berguna di sini: nilai seperti^\.envakan menonton file yang secara harfiah bernama^\.env. - Filter hooks mana yang dijalankan: ketika file yang dipantau berubah, nilai yang sama memfilter grup hook mana yang dijalankan menggunakan aturan matcher standar terhadap basename file yang berubah.
CLAUDE_ENV_FILE. Variabel yang ditulis ke file itu bertahan ke perintah Bash berikutnya untuk sesi, sama seperti dalam SessionStart hooks.
FileChanged input
Selain bidang input umum, FileChanged hooks menerimafile_path dan event.
FileChanged output
Selain bidang output JSON yang tersedia untuk semua hooks, FileChanged hooks dapat mengembalikanwatchPaths untuk secara dinamis memperbarui path file mana yang dipantau:
FileChanged hooks tidak memiliki kontrol keputusan. Mereka tidak dapat memblokir perubahan file dari terjadi.
WorktreeCreate
Dijalankan ketika worktree sedang dibuat, baik dariclaude --worktree atau dari subagent menggunakan isolation: "worktree". Secara default Claude Code membuat salinan kerja terisolasi dengan git worktree. Mengonfigurasi hook WorktreeCreate menggantikan perilaku git default itu, memungkinkan Anda menggunakan sistem kontrol versi berbeda seperti SVN, Perforce, atau Mercurial.
Karena hook menggantikan perilaku default sepenuhnya, .worktreeinclude tidak diproses. Jika Anda perlu menyalin file konfigurasi lokal seperti .env ke worktree baru, lakukan di dalam skrip hook Anda.
Hook harus mengembalikan path ke direktori worktree yang dibuat. Claude Code menggunakan path ini sebagai direktori kerja untuk sesi terisolasi. Lihat WorktreeCreate output untuk cara setiap tipe hook mengembalikan path.
Contoh ini membuat salinan kerja SVN dan mencetak path untuk Claude Code gunakan. Ganti URL repositori dengan milik Anda sendiri:
name worktree dari input JSON di stdin, melakukan checkout salinan segar ke direktori baru, dan mencetak path direktori. echo pada baris terakhir adalah apa yang Claude Code baca sebagai path worktree. Alihkan output lainnya ke stderr sehingga tidak mengganggu path.
WorktreeCreate input
Selain bidang input umum, WorktreeCreate hooks menerima bidangname. Ini adalah pengenal slug untuk worktree baru, baik ditentukan oleh pengguna atau auto-generated, misalnya bold-oak-a3f2.
WorktreeCreate output
WorktreeCreate hooks tidak menggunakan model keputusan allow/block standar. Sebaliknya, kesuksesan atau kegagalan hook menentukan hasil. Hook harus mengembalikan path ke direktori worktree yang dibuat:- Command hooks (
type: "command"): cetak path sebagai baris non-kosong terakhir dari stdout. Claude Code menghapus kode escape ANSI sebelum membaca baris itu, jadi banner startup shell yang dicetak sebelumechoAnda diabaikan. Alihkan output hook lainnya ke stderr. - HTTP hooks (
type: "http"): kembalikan{ "hookSpecificOutput": { "hookEventName": "WorktreeCreate", "worktreePath": "/absolute/path" } }dalam badan respons.
-p itu macet selama sekitar 30 detik sebelum keluar dengan kode 0.
WorktreeRemove
Dijalankan ketika worktree sedang dihapus, baik ketika Anda keluar dari sesi--worktree dan memilih untuk menghapusnya, atau ketika subagent dengan isolation: "worktree" selesai. Ini adalah pasangan cleanup untuk WorktreeCreate.
Untuk git-based worktrees, Claude Code menangani cleanup secara otomatis dengan git worktree remove. Jika Anda mengonfigurasi hook WorktreeCreate untuk sistem kontrol versi non-git, pasangkan dengan hook WorktreeRemove untuk menangani cleanup. Tanpanya, direktori worktree ditinggalkan di disk.
Claude Code meneruskan path yang dikembalikan oleh WorktreeCreate sebagai worktree_path dalam input hook. Contoh ini membaca path itu dan menghapus direktori:
WorktreeRemove input
Selain bidang input umum, WorktreeRemove hooks menerima bidangworktree_path, yang merupakan path absolut ke worktree yang sedang dihapus.
PreCompact
Dijalankan sebelum Claude Code akan menjalankan operasi compact. Nilai matcher menunjukkan apakah compaction dipicu secara manual atau otomatis:
Keluar dengan kode 2 untuk memblokir compaction. Untuk manual
/compact, pesan stderr ditampilkan ke pengguna. Anda juga dapat memblokir dengan mengembalikan JSON dengan "decision": "block".
Memblokir automatic compaction memiliki efek berbeda tergantung pada kapan dijalankan. Jika compaction dipicu secara proaktif sebelum batas konteks, Claude Code melewatinya dan percakapan berlanjut tanpa compaction. Jika compaction dipicu untuk pulih dari kesalahan batas konteks yang sudah dikembalikan oleh API, kesalahan yang mendasar muncul dan permintaan saat ini gagal.
PreCompact input
Selain bidang input umum, PreCompact hooks menerimatrigger dan custom_instructions. Untuk manual, custom_instructions berisi apa yang diteruskan pengguna ke /compact. Untuk auto, custom_instructions kosong.
PostCompact
Dijalankan setelah Claude Code menyelesaikan operasi compact. Gunakan event ini untuk bereaksi terhadap status compacted baru, misalnya untuk mencatat ringkasan yang dihasilkan atau memperbarui status eksternal. Nilai matcher yang sama berlaku seperti untukPreCompact:
PostCompact input
Selain bidang input umum, PostCompact hooks menerimatrigger dan compact_summary. Bidang compact_summary berisi ringkasan percakapan yang dihasilkan oleh operasi compact.
SessionEnd
Dijalankan ketika sesi Claude Code berakhir. Berguna untuk tugas cleanup, logging statistik sesi, atau menyimpan status sesi. Mendukung matchers untuk memfilter berdasarkan alasan keluar. Bidangreason dalam input hook menunjukkan mengapa sesi berakhir:
SessionEnd input
Selain bidang input umum, SessionEnd hooks menerima bidangreason menunjukkan mengapa sesi berakhir. Lihat tabel reason di atas untuk semua nilai.
/clear, dan beralih sesi melalui /resume interaktif. Jika hook memerlukan lebih banyak waktu, atur per-hook timeout dalam konfigurasi hook. Anggaran keseluruhan secara otomatis dinaikkan ke timeout per-hook tertinggi yang dikonfigurasi dalam file pengaturan, hingga 60 detik. Timeout yang ditetapkan pada hooks yang disediakan plugin tidak menaikkan anggaran. Untuk menimpa anggaran secara eksplisit, atur variabel lingkungan CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS dalam milidetik.
Elicitation
Dijalankan ketika server MCP meminta input pengguna mid-task. Secara default, Claude Code menampilkan dialog interaktif untuk pengguna merespons. Hooks dapat mengintersepsi permintaan ini dan merespons secara programatis, melewati dialog sepenuhnya. Bidang matcher mencocokkan nama server MCP.Elicitation input
Selain bidang input umum, Elicitation hooks menerimamcp_server_name, message, dan bidang opsional mode, url, elicitation_id, dan requested_schema.
Untuk form-mode elicitation, kasus paling umum:
Elicitation output
Untuk merespons secara programatis tanpa menampilkan dialog, kembalikan objek JSON denganhookSpecificOutput:
Kode keluar 2 menolak elicitation dan menampilkan stderr ke pengguna.
ElicitationResult
Dijalankan setelah pengguna merespons elicitation MCP. Hooks dapat mengamati, memodifikasi, atau memblokir respons sebelum dikirim kembali ke server MCP. Bidang matcher mencocokkan nama server MCP.ElicitationResult input
Selain bidang input umum, ElicitationResult hooks menerimamcp_server_name, action, dan bidang opsional mode, elicitation_id, dan content.
ElicitationResult output
Untuk menimpa respons pengguna, kembalikan objek JSON denganhookSpecificOutput:
Kode keluar 2 memblokir respons, mengubah tindakan efektif menjadi
decline.
Prompt-based hooks
Selain command, HTTP, dan MCP tool hooks, Claude Code mendukung prompt-based hooks (type: "prompt") yang menggunakan LLM untuk mengevaluasi apakah akan mengizinkan atau memblokir tindakan, dan agent hooks (type: "agent") yang spawn agentic verifier dengan akses tool. Tidak semua events mendukung setiap tipe hook.
Events yang mendukung semua lima tipe hook (command, http, mcp_tool, prompt, dan agent):
PermissionDeniedPermissionRequestPostToolBatchPostToolUsePostToolUseFailurePreToolUseStopSubagentStopTaskCompletedTaskCreatedTeammateIdleUserPromptExpansionUserPromptSubmit
command, http, dan mcp_tool tetapi bukan prompt atau agent:
ConfigChangeCwdChangedElicitationElicitationResultFileChangedInstructionsLoadedNotificationPostCompactPreCompactSessionEndStopFailureSubagentStartWorktreeCreateWorktreeRemove
SessionStart dan Setup mendukung hooks command dan mcp_tool. Mereka tidak mendukung hooks http, prompt, atau agent.
Bagaimana prompt-based hooks bekerja
Alih-alih menjalankan perintah Bash, prompt-based hooks:- Mengirimkan input hook dan prompt Anda ke model Claude, Haiku secara default
- LLM merespons dengan JSON terstruktur yang berisi keputusan
- Claude Code memproses keputusan secara otomatis
Konfigurasi prompt hook
Aturtype ke "prompt" dan sediakan string prompt alih-alih command. Gunakan placeholder $ARGUMENTS untuk menyuntikkan data JSON input hook ke dalam teks prompt Anda. Claude Code mengirimkan prompt gabungan dan input ke model Claude cepat, yang mengembalikan keputusan JSON.
Hook Stop ini meminta LLM untuk mengevaluasi apakah semua tugas selesai sebelum mengizinkan Claude selesai:
Skema respons
LLM harus merespons dengan JSON yang berisi:
Apa yang terjadi pada
ok: false tergantung pada event:
StopdanSubagentStop: alasan diumpankan kembali ke Claude sebagai instruksi berikutnya dan giliran berlanjutPreToolUse: panggilan tool ditolak dan alasan dikembalikan ke Claude sebagai kesalahan tool, setara denganpermissionDecision: "deny"dari command hookPostToolUse: secara default giliran berakhir dan alasan muncul dalam chat sebagai baris peringatan. AturcontinueOnBlock: trueuntuk umpankan alasan kembali ke Claude dan lanjutkan giliran alih-alihPostToolBatch,UserPromptSubmit, danUserPromptExpansion: giliran berakhir dan alasan muncul sebagai baris peringatan. Events ini mengakhiri giliran padadecision: "block"terlepas daricontinuePostToolUseFailure,TaskCreated, danTaskCompleted: alasan dikembalikan ke Claude sebagai kesalahan tool, mirip denganPreToolUseTeammateIdle: secara default rekan kerja berhenti dan alasan muncul sebagai baris peringatan. AturcontinueOnBlock: trueuntuk umpankan alasan kembali ke rekan kerja dan biarkan tetap bekerja alih-alihPermissionRequest:ok: falsetidak berpengaruh. Untuk menolak persetujuan dari hook, gunakan command hook yang mengembalikanhookSpecificOutput.decision.behavior: "deny"PermissionDenied:ok: falsetidak berpengaruh karena penolakan sudah terjadi. Satu-satunya output yang dibaca event ini adalahhookSpecificOutput.retry, yang prompt dan agent hooks tidak dapat atur — mereka berjalan pada event ini, tetapi output mereka diabaikan. Gunakan command hook untuk mengembalikanretry
Periksa beberapa kondisi sebelum berhenti
HookStop ini menggunakan prompt detail untuk memeriksa tiga kondisi sebelum mengizinkan Claude berhenti. Hooks SubagentStop menggunakan format yang sama untuk mengevaluasi apakah subagent harus berhenti. Jika "ok" adalah false, Claude terus bekerja dengan alasan yang disediakan sebagai instruksi berikutnya:
Agent-based hooks
Agent-based hooks (type: "agent") seperti prompt-based hooks tetapi dengan akses tool multi-turn. Alih-alih pemanggilan LLM tunggal, hook agent spawn subagent yang dapat membaca file, mencari kode, dan memeriksa codebase untuk memverifikasi kondisi. Agent hooks mendukung events yang sama seperti prompt-based hooks.
Bagaimana agent hooks bekerja
Ketika hook agent dijalankan:- Claude Code spawn subagent dengan prompt Anda dan JSON input hook
- Subagent dapat menggunakan tools seperti Read, Grep, dan Glob untuk menyelidiki
- Setelah hingga 50 turn, subagent mengembalikan keputusan terstruktur
{ "ok": true/false } - Claude Code memproses keputusan dengan cara yang sama seperti prompt hook
Konfigurasi agent hook
Aturtype ke "agent" dan sediakan string prompt. Bidang konfigurasi sama seperti prompt hooks, dengan timeout default lebih lama:
Skema respons sama seperti prompt hooks:
{ "ok": true } untuk mengizinkan atau { "ok": false, "reason": "..." } untuk memblokir.
Hook Stop ini memverifikasi bahwa semua unit tests lulus sebelum mengizinkan Claude selesai:
Jalankan hooks di latar belakang
Secara default, hooks memblokir eksekusi Claude sampai selesai. Untuk tugas yang berjalan lama seperti deployments, test suites, atau panggilan API eksternal, atur"async": true untuk menjalankan hook di latar belakang sementara Claude terus bekerja. Async hooks tidak dapat memblokir atau mengontrol perilaku Claude: bidang respons seperti decision, permissionDecision, dan continue tidak berpengaruh, karena tindakan yang akan mereka kontrol sudah selesai.
Konfigurasi async hook
Tambahkan"async": true ke konfigurasi command hook untuk menjalankannya di latar belakang tanpa memblokir Claude. Bidang ini hanya tersedia pada hooks type: "command".
Hook ini menjalankan skrip test setelah setiap pemanggilan tool Write. Claude terus bekerja segera sementara run-tests.sh dijalankan hingga 120 detik. Ketika skrip selesai, outputnya disampaikan pada turn percakapan berikutnya:
timeout menetapkan waktu maksimum dalam detik untuk proses latar belakang. Jika tidak ditentukan, async hooks menggunakan default 10 menit yang sama seperti sync hooks.
Bagaimana async hooks dijalankan
Ketika async hook dijalankan, Claude Code memulai proses hook dan segera melanjutkan tanpa menunggu selesai. Hook menerima JSON input yang sama melalui stdin seperti hook sinkron. Setelah proses latar belakang keluar, jika hook menghasilkan respons JSON dengan bidangadditionalContext, konten itu disampaikan ke Claude sebagai konteks pada turn percakapan berikutnya. Bidang systemMessage ditampilkan kepada Anda, bukan kepada Claude.
Claude Code memvalidasi respons JSON tersebut terhadap output schema yang sama seperti hooks sinkron, dan menghapus bidang apa pun yang nilainya memiliki tipe yang salah, seperti systemMessage yang bukan string, alih-alih menyampaikannya. Jalankan dengan --debug untuk melihat peringatan yang menyebutkan setiap bidang yang dihapus. Sebelum v2.1.202, output JSON yang tidak terbentuk dengan baik dari async hook dapat menghancurkan sesi, dan kerusakan terulang setiap kali sesi dilanjutkan.
Notifikasi penyelesaian async hook ditekan secara default. Untuk melihatnya, aktifkan mode verbose dengan Ctrl+O atau mulai Claude Code dengan --verbose.
Jalankan tests setelah perubahan file
Hook ini memulai test suite di latar belakang setiap kali Claude menulis file, kemudian melaporkan hasil kembali ke Claude ketika tests selesai. Simpan skrip ini ke.claude/hooks/run-tests-async.sh dalam proyek Anda dan buat dapat dijalankan dengan chmod +x:
.claude/settings.json dalam akar proyek Anda. Flag async: true memungkinkan Claude terus bekerja sementara tests dijalankan:
Keterbatasan
Async hooks memiliki beberapa batasan dibandingkan dengan hooks sinkron:- Hanya hooks
type: "command"yang mendukungasync. Prompt-based hooks tidak dapat dijalankan secara asinkron. - Async hooks tidak dapat memblokir pemanggilan tool atau mengembalikan keputusan. Pada saat hook selesai, tindakan pemicu sudah dilanjutkan.
- Output hook disampaikan pada turn percakapan berikutnya. Jika sesi idle, respons menunggu sampai interaksi pengguna berikutnya. Pengecualian: hook
asyncRewakeyang keluar dengan kode 2 membangunkan Claude segera bahkan ketika sesi idle. - Setiap eksekusi membuat proses latar belakang terpisah. Tidak ada deduplikasi di seluruh beberapa penjalankan hook async yang sama.
Pertimbangan keamanan
Penafian
Command hooks dijalankan dengan izin pengguna sistem penuh Anda.Praktik terbaik keamanan
Ingat praktik-praktik ini saat menulis hooks:- Validasi dan sanitasi input: jangan pernah mempercayai data input secara membabi buta
- Selalu kutip variabel shell: gunakan
"$VAR"bukan$VAR - Blokir path traversal: periksa
..dalam path file - Gunakan path absolut: tentukan path lengkap untuk skrip. Dalam bentuk exec, gunakan
${CLAUDE_PROJECT_DIR}dan path tidak perlu dikutip. Dalam bentuk shell, bungkus dengan tanda kutip ganda - Lewati file sensitif: hindari
.env,.git/, keys, dll.
Windows PowerShell tool
Di Windows, Anda dapat menjalankan hook individual dalam PowerShell dengan menetapkan"shell": "powershell" pada command hook. Hooks spawn PowerShell secara langsung, jadi ini bekerja terlepas dari apakah CLAUDE_CODE_USE_POWERSHELL_TOOL diatur. Claude Code auto-detects pwsh.exe, executable PowerShell 7 dan yang lebih baru, dan fallback ke powershell.exe untuk Windows PowerShell 5.1.
${CLAUDE_PROJECT_DIR} atau $env:CLAUDE_PROJECT_DIR. Mulai dari v2.1.198, Claude Code menulis ulang placeholder ${CLAUDE_PROJECT_DIR}, ${CLAUDE_PLUGIN_ROOT}, dan ${CLAUDE_PLUGIN_DATA} dalam perintah bentuk shell PowerShell ke bentuk ${env:NAME} PowerShell, baik hook didefinisikan dalam settings.json, plugin, atau skill. PowerShell kemudian menyelesaikan nilai dari lingkungan yang diekspor setelah parsing, jadi placeholder bekerja di dalam string dengan tanda kutip ganda tetapi tidak di dalam string dengan tanda kutip tunggal, di mana PowerShell tidak pernah memperluas variabel.
Sebelum v2.1.198, penulisan ulang ini hanya berlaku untuk plugin hooks. Pada versi yang lebih awal, hook settings.json memerlukan bentuk $env: atau exec form, di mana ${CLAUDE_PROJECT_DIR} diganti di setiap elemen args terlepas dari di mana hook didefinisikan.
Jangan tulis ejaan bare $CLAUDE_PROJECT_DIR dalam hook PowerShell. PowerShell menguraikannya sebagai variabel lokal yang tidak terdefinisi dan menyelesaikannya ke $null, yang meninggalkan jalur skrip tanpa awalan root proyeknya. Claude Code tidak menulis ulang bentuk itu; sebaliknya, ia mencatat peringatan dalam debug log.
Contoh di bawah menunjukkan hook settings.json yang menjalankan skrip proyek dengan bentuk $env:, yang bekerja di setiap versi:
Debug hooks
Detail eksekusi hook, termasuk hook mana yang cocok, kode keluar mereka, dan stdout dan stderr lengkap, ditulis ke file debug log. Mulai Claude Code denganclaude --debug-file <path> untuk menulis log ke lokasi yang diketahui, atau jalankan claude --debug dan baca log di ~/.claude/debug/<session-id>.txt. Flag --debug tidak mencetak ke terminal.
CLAUDE_CODE_DEBUG_LOG_LEVEL=verbose untuk melihat baris log tambahan seperti jumlah matcher hook dan pencocokan query.
Untuk troubleshooting masalah umum seperti hooks tidak dijalankan, Stop hooks yang terus memblokir, atau kesalahan konfigurasi, lihat Limitations and troubleshooting dalam panduan. Untuk panduan diagnostik yang lebih luas mencakup /context, /doctor, dan precedence pengaturan, lihat Debug your config.