Hook Claude Code: Event, Exit Code 2, dan Keamanan
Pahami lokasi hook Claude Code, event yang dijalankan, dampak exit code 2 pada pemanggilan tool, serta risiko keamanan saat menjalankan perintah otomatis.
Apa itu hook Claude Code
Hook Claude Code adalah perintah shell yang dijalankan Claude Code secara otomatis pada titik-titik tertentu dalam siklus hidupnya. Inilah perbedaan utama antara hook dan file aturan. Instruksi dalam CLAUDE.md adalah saran, dan model mempertimbangkannya bersama semua hal lain dalam konteksnya. Hook adalah kode, dan kode tersebut dijalankan terlepas dari apakah model menyetujuinya. Jika agent Anda terus melewati formatter yang sudah Anda jelaskan dua kali, Anda tidak memerlukan instruksi yang lebih tegas. Anda memerlukan hook.
Mekanismenya sederhana. Anda mendaftarkan perintah dalam file pengaturan di bawah nama event. Saat event tersebut terjadi, Claude Code menjalankan perintah Anda dan menulis data event ke standard input (stdin) sebagai JSON (JavaScript object notation). Perintah Anda membaca data tersebut, menjalankan tugasnya, lalu mengembalikan status keluar. Exit 2 dari hook PreToolUse membatalkan pemanggilan tool sebelum dijalankan, dan apa pun yang ditulis skrip Anda ke standard error (stderr) akan dikirim kembali ke model sebagai alasannya.
Nama event dan nama field di sini berasal dari referensi hooks Claude Code, yang diperiksa pada August 2026 terhadap release 2.1.232. Permukaan ini berubah dengan cepat, jadi periksa referensi untuk versi Anda sendiri sebelum menyalin JSON dari posting blog mana pun, termasuk artikel ini. Tampilkan milik Anda dengan claude --version.
Lokasi konfigurasi hook
Hook adalah blok JSON dalam file pengaturan. Enam lokasi dapat menyimpan hook, dan cakupan file menentukan cakupan hook tersebut.
~/.claude/settings.json: setiap project di mesin Anda, tetapi tidak di mesin pengguna lain..claude/settings.json: satu project, di-commit ke repository, sehingga setiap orang yang melakukan clone mendapat hook tersebut..claude/settings.local.json: satu project, hanya di mesin Anda.- Pengaturan kebijakan terkelola: berlaku di seluruh organisasi dan ditetapkan oleh administrator.
hooks/hooks.jsondi dalam plugin, aktif selama plugin tersebut diaktifkan.- Frontmatter skill atau subagent, aktif selama komponen tersebut digunakan.
Entri hook dari file-file ini digabungkan, bukan saling menimpa. File pengaturan project menambahkan hook-nya ke hook dalam pengaturan pengguna, bukan menggantikannya. Karena itu, satu event dapat memiliki beberapa hook dari beberapa file. Pengaturan "disableAllHooks": true menonaktifkan hook tersebut, dengan satu pengecualian: hook dari pengaturan kebijakan terkelola tetap berjalan, kecuali pengaturan itu juga diterapkan dalam pengaturan terkelola.
Jalankan /hooks dalam session untuk menampilkan setiap hook yang saat ini terdaftar, dikelompokkan berdasarkan event, beserta file sumber dan matcher masing-masing. Menu ini hanya dapat dibaca, jadi ubah hook dengan mengedit file pengaturan. File watcher biasanya mendeteksi perubahan tersebut tanpa perlu restart.
Event hook Claude Code yang tersedia
Rilis 2.1.232 mencantumkan tiga puluh satu event, mulai dari SessionStart hingga SessionEnd, yang mencakup compaction, subagent, worktree, dan file konfigurasi. Pekerjaan administrasi server biasanya hanya menggunakan beberapa di antaranya.
PreToolUse: sebelum pemanggilan tool dijalankan. Event ini dapat memblokir pemanggilan.PostToolUse: setelah pemanggilan tool berhasil.PostToolUseFailureberjalan jika pemanggilan gagal. Jadi, hook yang harus melihat setiap hasil memerlukan keduanya.PermissionRequest: saat pemanggilan tool memerlukan keputusan izin. Pada saat inilah prompt persetujuan akan muncul.UserPromptSubmit: saat Anda mengirimkan prompt, sebelum Claude memprosesnya. Apa pun yang dicetak hook ini ke stdout akan ditambahkan ke konteks model.SessionStartdanSessionEnd: pada setiap akhir sesi.SessionStartjuga berjalan setelah compaction, dengan nilai matchercompact.Stop: saat Claude selesai merespons. Event ini berjalan sekali untuk setiap turn, bukan sekali untuk setiap task yang selesai.
Setiap grup memiliki matcher yang menentukan occurrence yang menjalankan hook. Pada event tool, matcher memfilter berdasarkan nama tool. Jadi, "Edit|Write" berjalan pada pengeditan file dan tidak pada occurrence lain. Matcher peka huruf besar-kecil. Matcher kosong berjalan pada setiap occurrence. Tool dari server MCP (model context protocol) diberi nama mcp__<server>__<tool>. Jadi, matcher "mcp__github__.*" hanya menangkap tool dari satu server dan mengabaikan server lainnya.
Hook Stop memiliki perilaku penting yang perlu diketahui sebelum Anda membuatnya. Hook Stop yang memblokir akan mengirim model kembali untuk bekerja, dan Claude Code akan mengabaikan hook tersebut setelah delapan pemblokiran berturut-turut. Baca field stop_hook_active dari input hook dan keluar dengan kode 0 jika nilainya true. Jika tidak, hook akan terus berulang hingga mencapai batas tersebut.
What a hook receives on stdin
When Claude is about to run npm test, a PreToolUse hook on Bash reads this on stdin:
{
"session_id": "abc123",
"cwd": "/home/deploy/myproject",
"hook_event_name": "PreToolUse",
"tool_name": "Bash",
"tool_input": {
"command": "npm test"
}
}Every event carries session_id, cwd, permission_mode, transcript_path and hook_event_name. The tool events add tool_name, tool_input and tool_use_id. Other events carry their own fields: UserPromptSubmit gets the prompt text, and SessionStart gets a source of startup, resume, clear, compact or fork.
jq is the usual way to read this inside a shell script, and a minimal server image does not have it. Install it first with sudo apt install -y jq on Ubuntu and Debian.
Dampak status keluar terhadap pemanggilan alat yang sedang berlangsung
Ada tiga hasil.
- Exit 0 berarti hook Anda tidak menyampaikan keberatan. Pada
PreToolUse, ini tidak sama dengan persetujuan, dan alur izin normal tetap berjalan. PadaUserPromptSubmitdanSessionStart, stdout ditambahkan ke konteks model. - Exit 2 memblokir tindakan pada event yang dapat diblokir, termasuk
PreToolUse, dan stderr menjadi alasan yang ditampilkan kepada model. Pada event yang tidak dapat diblokir, sepertiPostToolUse, pemblokiran diabaikan, tetapi stderr tetap diteruskan kepada model sebagai umpan balik. - Kode keluar lainnya adalah error yang tidak memblokir. Tindakan tetap dilanjutkan. Transkrip menampilkan pemberitahuan error hook yang memuat baris pertama stderr setelah teks
Failed with non-blocking status code:.
Untuk hasil selain memblokir atau tidak melakukan apa-apa, gunakan exit 0 dan cetak objek JSON ke stdout. Hook PreToolUse mengambil keputusan dengan permissionDecision:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Database drops go through a migration, not through the agent."
}
}"allow" melewati prompt interaktif, "deny" membatalkan pemanggilan dan mengirimkan alasannya kepada model, sedangkan "ask" menampilkan prompt seperti biasa. Pilih satu gaya untuk setiap hook. Mencampur exit 2 dengan keputusan JSON pada stdout menghasilkan perilaku yang harus Anda telusuri sendiri.
Jika beberapa hook cocok dengan satu event, hook tersebut berjalan secara paralel dan semuanya berjalan hingga selesai. deny dari satu hook tidak menghentikan hook lain yang berjalan bersamaan. Dengan demikian, hook pencatatan tetap menulis barisnya sementara hook guardrail menolak pemanggilan yang sama. Claude Code kemudian menggabungkan semua jawaban dan mempertahankan keputusan yang paling ketat, dengan urutan deny, defer, ask, allow.
Contoh 1: blokir perintah destruktif sebelum dijalankan
Simpan ini sebagai .claude/hooks/block-destructive.sh di project Anda:
#!/bin/bash
# Deny a Bash tool call whose command matches a banned pattern.
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
for pattern in 'rm -rf /' 'mkfs' 'dd if=' 'DROP TABLE'; do
if printf '%s' "$COMMAND" | grep -qiF -- "$pattern"; then
echo "Blocked by policy: the command matches '$pattern'. A human runs this one." >&2
exit 2
fi
done
exit 0Jadikan file tersebut executable, lalu daftarkan pada PreToolUse di .claude/settings.json:
chmod +x .claude/hooks/block-destructive.sh{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-destructive.sh",
"timeout": 10,
"statusMessage": "Checking the command against policy"
}
]
}
]
}
}Uji script tersebut secara manual sebelum mempercayainya, karena hook yang gagal saat memproses inputnya sendiri akan gagal secara terbuka:
echo '{"tool_name":"Bash","tool_input":{"command":"rm -rf /var/lib/postgresql"}}' \
| .claude/hooks/block-destructive.sh
echo $?Anda akan melihat baris Blocked by policy: pada stderr dan exit code 2. Berikan perintah yang aman, seperti ls -la. Seharusnya tidak ada output dan exit code yang dihasilkan adalah 0. Dalam sebuah session, pemanggilan yang ditolak muncul dalam transcript dengan pesan Anda sebagai alasannya. Model membaca pesan tersebut dan menyesuaikan tindakannya.
Ada satu properti yang membuat konfigurasi ini layak digunakan: hook PreToolUse dijalankan sebelum pemeriksaan permission-mode, dalam setiap permission mode. Karena itu, penolakan tetap berlaku bahkan dengan bypassPermissions. Inilah yang membuat hook berguna bersama mode otomatis Claude Code dan pengaturan permission-nya, saat prompt dikurangi tetapi hook tetap dijalankan.
Pahami batasannya. Pencocokan pola pada string perintah adalah guardrail untuk mencegah agent bertindak ceroboh. Ini bukan batasan terhadap agent yang sengaja menghindarinya, karena perintah yang sama dapat ditulis dalam bentuk yang tidak pernah dilihat oleh grep. Aturan yang benar-benar ketat harus diterapkan dalam sistem permission dan pada account yang digunakan untuk menjalankan proses.
Contoh 2: format dan lint setelah setiap pengeditan
PostToolUse dengan matcher Edit|Write dijalankan setelah alat pengeditan file apa pun. Simpan konfigurasi ini sebagai .claude/hooks/after-edit.sh:
#!/bin/bash
# Format the edited file, then report lint failures back to the model.
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
[ -z "$FILE" ] && exit 0
case "$FILE" in
*.py)
ruff format "$FILE" >/dev/null 2>&1
if ! ruff check "$FILE" >&2; then
exit 2
fi
;;
*.sh)
if ! shellcheck "$FILE" >&2; then
exit 2
fi
;;
esac
exit 0{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/after-edit.sh",
"timeout": 60
}
]
}
]
}
}Minta Claude menambahkan fungsi dengan indentasi yang buruk ke file Python, lalu buka file tersebut. Fungsi itu akan kembali dalam format yang benar. Ini memastikan bahwa hook telah berjalan, karena hook yang berhasil tidak menampilkan apa pun dalam percakapan.
Kode keluar 2 di sini tidak membatalkan apa pun. PostToolUse dijalankan setelah alat selesai dieksekusi, sehingga pengeditan tetap tersimpan di disk. Kode keluar 2 membuat output ruff check diteruskan ke model sebagai umpan balik, sehingga model memperbaiki error yang baru saja dibuatnya sebelum melanjutkan. Inilah perbedaan antara kegagalan lint yang baru ditemukan saat commit dan kegagalan yang diperbaiki agen pada giliran yang sama.
Dua batasan matcher penting di sini. Edit|Write tidak melihat file yang diubah oleh perintah shell, dan Claude cukup sering menulis file melalui Bash sehingga celah ini nyata. Untuk cakupan pada setiap pemanggilan, cocokkan Bash juga dan minta skrip mencantumkan file yang berubah dengan git status --porcelain. Untuk cakupan satu kali per giliran, masukkan pemindaian ke dalam hook Stop.
Contoh 3: mencatat setiap pemanggilan tool untuk audit
Matcher kosong pada PostToolUse berjalan pada setiap tool. Mengirim catatan ke system journal, bukan ke file di direktori home, membuatnya tidak dapat dijangkau oleh shell milik agent:
{
"hooks": {
"PostToolUse": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "jq -c '{time: now|todate, session: .session_id, cwd: .cwd, tool: .tool_name, input: .tool_input}' | logger -t claude-code -p local0.info"
}
]
}
]
}
}Baca kembali catatan tersebut dengan journalctl -t claude-code -o cat | tail -n 5. Anda akan melihat satu baris JSON untuk setiap pemanggilan tool, dengan catatan terbaru di bagian akhir. Jika tidak ada catatan yang muncul, berarti hook tidak berjalan. Bagian pemecahan masalah di bawah membahas kondisi tersebut.
Tambahkan blok yang sama di bawah PostToolUseFailure untuk mencatat pemanggilan yang gagal, karena PostToolUse hanya berjalan saat berhasil dan perintah yang gagal biasanya merupakan perintah yang paling perlu diperiksa. Alasan menggunakan logger, bukan menambahkan catatan ke file di direktori home, adalah kepemilikan: hook berjalan sebagai user yang sama dengan shell milik agent. Karena itu, apa pun yang dapat ditambahkan oleh user tersebut juga dapat dipotong isinya oleh user tersebut. Journal ditulis oleh systemd-journald menggunakan akunnya sendiri.
Berapa lama hook dapat berjalan
The data behind this chart
[
{
"label": "command, http or mcp_tool hook",
"default_timeout_seconds": 600
},
{
"label": "agent hook",
"default_timeout_seconds": 60
},
{
"label": "prompt hook",
"default_timeout_seconds": 30
},
{
"label": "command hook on UserPromptSubmit",
"default_timeout_seconds": 30
},
{
"label": "command hook on MessageDisplay",
"default_timeout_seconds": 10
},
{
"label": "any hook on SessionEnd",
"default_timeout_seconds": 1.5
}
]Secara default, command hook mendapat waktu 600 detik, yaitu sepuluh menit. Beberapa event memperpendek batas ini secara signifikan. Semua hook SessionEnd berbagi anggaran waktu 1.5 detik, sehingga pembersihan pada akhir sesi harus berlangsung cepat. Namun, dengan menetapkan timeout yang lebih panjang pada hook, anggaran bersama tersebut meningkat hingga batas 60 detik.
Hook yang mencapai batas waktunya akan dibatalkan dan tidak menghasilkan keputusan. Untuk PreToolUse guardrail, artinya hook tersebut tidak memblokir: pemanggilan tool berlanjut ke alur izin normal. Karena itu, buat skrip guardrail tetap singkat. Untuk pekerjaan lambat yang tidak perlu ditunggu, seperti mengirim log ke lokasi lain, tetapkan "async": true agar hook berjalan di latar belakang tanpa menunda pemanggilan tool.
Hook, file aturan, skill, dan server MCP
Empat hal ini sering tertukar karena semuanya mengubah perilaku agent. Hanya satu di antaranya yang tidak lagi sekadar menjadi saran.
File aturan (CLAUDE.md atau file di bawah .claude/rules/) adalah teks yang dimuat ke dalam konteks model. File ini membentuk perilaku, tetapi tidak menegakkan apa pun. Dalam percakapan yang panjang, diff yang besar, dan permintaan pengguna yang baru, satu baris di dalamnya dapat terabaikan. Inilah mekanisme umum yang menyebabkan agent mengabaikan instruksi yang Anda tulis.
Skill adalah folder berisi instruksi dan skrip yang dimuat model ketika menilai bahwa skill tersebut relevan. Penilaian itu merupakan inti dari skill sekaligus batasannya: model tetap yang memutuskan. Anda dapat melihat kedua sisi ini pada skill seperti Ponytail, yang mengarahkan agent untuk menerapkan perubahan terkecil yang berfungsi, karena skill tersebut membentuk cara seluruh tugas dikerjakan dengan cara yang tidak dapat dilakukan hook, dan hanya selama model memilih untuk memuatnya.
Server MCP (model context protocol) memberi model alat baru untuk dipanggil. Server ini memperluas hal-hal yang dapat dijangkau agent. Server ini tidak membuat agent menggunakannya, dan merupakan proses terpisah yang harus Anda operasikan. Pengoperasiannya juga merupakan tugas tersendiri: lihat menjalankan server MCP pada VPS.
Hook adalah satu-satunya dari empat hal ini yang berjalan tanpa dipilih oleh model. Gunakan file aturan untuk preferensi dan skill untuk prosedur yang harus diikuti model ketika berlaku. Gunakan hook untuk langkah yang harus dijalankan setiap kali atau untuk hal yang tidak boleh terjadi. Perbandingan yang lebih mendalam, termasuk kapan skill lebih tepat daripada file aturan, tersedia di perbandingan skill, MCP, dan file aturan.
Plugin adalah bentuk pengemasan, bukan mekanisme kelima. Plugin menggabungkan hook dan skill menjadi satu unit yang dapat diinstal. Dengan cara ini, tim dapat menerapkan pengaman yang sama pada setiap mesin: lihat cara kerja plugin Claude Code.
Keputusan keamanan pada VPS bersama
Hook adalah kode yang dipicu oleh agen dan dijalankan sebagai pengguna yang memulai Claude Code. Hook mewarisi lingkungan dan izin file pengguna tersebut. Pada laptop, ini merupakan pertanyaan tentang alur kerja. Pada VPS tempat agen berjalan tanpa pengawasan, ini merupakan pertanyaan keamanan dengan empat aspek praktis.
Hook dalam repositori adalah kode yang tidak Anda tulis. .claude/settings.json dikomit, sehingga proses clone repositori dan memulai sesi di dalamnya dapat mendaftarkan hook yang disertakan repositori tersebut. Claude Code menempatkan hook proyek di balik dialog kepercayaan workspace untuk folder itu. Artinya, menerima kepercayaan adalah saat Anda memutuskan untuk menjalankan hook tersebut. Baca blok hooks terlebih dahulu.
Hook dapat melihat seluruh input tool. Hook audit yang mencatat tool_input menulis setiap argumen dari setiap perintah ke dalam file, termasuk token apa pun yang kebetulan berada pada command line. Log tersebut kemudian memerlukan perlindungan yang sama seperti secret, dan hal ini merupakan bagian dari masalah yang lebih luas, yaitu menjauhkan secret dari jangkauan agen AI.
Hook dapat menulis ke dalam konteks model. Apa pun yang dicetak oleh hook SessionStart atau UserPromptSubmit ke stdout akan ditambahkan ke percakapan. Hook yang meneruskan teks dari luar, pelacak issue, atau file log akan memberikan teks yang tidak tepercaya kepada model seolah-olah Anda sendiri yang mengetiknya. Perlakukan stdout tersebut sebagai input, bukan sebagai output.
Hak istimewa adalah kontrol yang sebenarnya. Jalankan agen sebagai pengguna khusus tanpa hak istimewa, dengan hanya aturan sudo yang diperlukan. Deny PreToolUse tetap berguna, dan mekanisme ini memang dirancang sebagai upaya terbaik: dokumentasi referensi menyatakan hal yang sama tentang filter if dan mengarahkan Anda untuk menggunakan sistem izin jika memerlukan penolakan yang tegas. Aturan izin dan akun yang digunakan untuk menjalankan proses adalah bagian yang tetap efektif saat menghadapi tekanan.
Satu properti berlaku dalam setiap konfigurasi. Hook PreToolUse dijalankan sebelum pemeriksaan mode izin dalam setiap mode izin, sehingga hook yang mengembalikan deny akan memblokir tool bahkan dalam bypassPermissions. Hook dapat memperketat hal yang diizinkan oleh aturan izin. Hook tidak dapat melonggarkannya.
Mengapa hook saya tidak dijalankan?
Ikuti langkah-langkah ini secara berurutan. Setiap langkah menyebutkan gejala yang akan Anda lihat.
- Jalankan
/hooksdan periksa apakah hook muncul pada event yang diharapkan. Hook yang tidak muncul di menu biasanya berarti file pengaturan memiliki kesalahan sintaks JSON, karena koma di akhir dan komentar tidak diizinkan, atau file tersebut tidak berada di salah satu dari enam lokasi di atas. - Bandingkan matcher dengan nama tool secara persis. Matcher peka huruf besar-kecil, sehingga
"bash"tidak pernah cocok dengan toolBash. - Jalankan script secara manual dengan input contoh, seperti pada contoh 1 di atas. Kode keluar yang tidak sesuai harapan menunjukkan bug dalam script Anda. Claude Code melaporkannya sebagai error hook, bukan sebagai keputusan.
- Notifikasi yang berbunyi
jq: command not foundberartijqtidak tersedia pada mesin tersebut.command not founduntuk script Anda sendiri berarti path tidak dapat di-resolve. Gunakan${CLAUDE_PROJECT_DIR}atau path absolut. Jika script sama sekali tidak dijalankan, kemungkinan script tersebut tidak memiliki izin eksekusi. - Hook mencetak JSON yang valid, tetapi tidak terjadi apa-apa. Hook dalam bentuk shell dijalankan melalui
sh -c. Jika profil shell Anda mencetak banner, banner tersebut ditambahkan di depan JSON. Akibatnya, stdout tidak lagi diawali{, sehingga Claude Code membaca seluruh output sebagai teks biasa dan mengabaikan keputusan tersebut. Jika keluar dengan kode 0, tidak ada laporan di mana pun selain di debug log. Bungkus setiapechodalam profil Anda agar hanya dijalankan pada shell interaktif. - Jika masalah masih belum teratasi, mulai sesi dengan
claude --debug-file /tmp/claude.logdan jalankantail -f /tmp/claude.logdi terminal kedua. Debug log mencatat hook yang cocok, kode keluar yang dikembalikan masing-masing hook, serta semua output yang ditulisnya ke stdout dan stderr.
FAQ
Apa perbedaan antara hook Claude Code dan instruksi CLAUDE.md?
Instruksi CLAUDE.md adalah teks dalam konteks model. Instruksi tersebut harus berbagi perhatian dengan percakapan dan permintaan saat ini, dan model dapat menimbangnya terhadap keduanya. Hook adalah perintah shell yang dijalankan Claude Code pada titik tetap dalam siklus hidupnya. Hook dijalankan setiap kali event tersebut terjadi, terlepas dari keputusan model. Gunakan instruksi untuk preferensi. Gunakan hook untuk langkah yang harus selalu dijalankan atau tindakan yang tidak boleh pernah dijalankan.
Bagaimana cara menghentikan Claude Code agar tidak menjalankan perintah shell tertentu?
Daftarkan hook PreToolUse dengan matcher Bash yang membaca perintah dari .tool_input.command, menulis alasan ke stderr, lalu keluar dengan kode 2. Claude Code membatalkan pemanggilan tersebut dan menampilkan alasan Anda kepada model. Proses ini terjadi sebelum pemeriksaan permission mode, sehingga penolakan tetap berlaku dalam mode bypassPermissions. Pencocokan pola pada string perintah adalah pengamanan, bukan batas keamanan, karena perintah yang sama dapat ditulis dalam bentuk yang tidak cocok dengan pola. Karena itu, lengkapi dengan permission rules dan akun tanpa hak istimewa.
Hook saya mencetak JSON yang valid, tetapi tidak terjadi apa-apa. Mengapa?
Penyebab yang paling umum adalah shell profile Anda. Hook tanpa field args dijalankan melalui sh -c. Beberapa profile mencetak banner pada setiap shell, sehingga banner tersebut muncul di stdout sebelum JSON Anda. Karena output tidak lagi diawali {, Claude Code memperlakukan seluruh output sebagai teks biasa dan mengabaikan keputusan tersebut. Jika proses berakhir dengan kode 0, tidak ada apa pun yang dilaporkan dalam transcript. Lindungi setiap echo di profile Anda dengan pemeriksaan interactive shell. Kemudian, konfirmasikan perbaikannya dengan membaca debug log dari claude --debug-file /tmp/claude.log.
Apakah aman menjalankan hook Claude Code pada server bersama?
Hook dijalankan sebagai user yang memulai Claude Code, dengan permission file milik user tersebut. Karena itu, hook dapat melakukan apa pun yang dapat dilakukan akun tersebut. Dua kebiasaan ini mencakup sebagian besar risikonya: jalankan agent sebagai akun khusus tanpa hak istimewa dengan kebijakan sudo yang ketat, lalu baca blok hooks pada repository apa pun sebelum menerima dialog kepercayaan workspace karena project hook disertakan dalam .claude/settings.json. Tetapkan "disableAllHooks": true dalam file settings jika Anda tidak ingin satu pun hook tersebut dijalankan.