Panduan Claude Code Hooks: cek aman sebelum dan sesudah kerja
Panduan Claude Code Hooks untuk pemula: blokir command berbahaya, simpan log, jalankan format, lint, dan test otomatis.
Claude Code Hooks adalah pemeriksaan otomatis yang berjalan sebelum atau sesudah Claude Code melakukan aksi. Daripada selalu menulis “jangan jalankan command berbahaya”, “format file setelah edit”, atau “jalankan test”, aturan itu bisa dipasang langsung ke workflow proyek.
Model paling mudah untuk pemula adalah ini: PreToolUse adalah rem, PostToolUse adalah perawatan, UserPromptSubmit adalah catatan masuk, dan Stop adalah pemeriksaan sebelum selesai. Hooks tidak menggantikan review manusia, permission, atau CI. Hooks membuat pemeriksaan berulang lebih sulit terlupakan.
Artikel ini mengikuti referensi resmi Claude Code Hooks dan dokumentasi resmi settings. Untuk konteks proyek, baca juga praktik terbaik CLAUDE.md. Untuk desain keamanan yang lebih luas, kombinasikan dengan panduan permission Claude Code.
Empat event yang perlu dipahami dulu
Claude Code punya banyak event Hooks, tetapi sebagian besar tim bisa mulai dari empat event berikut.
| Event | Cocok untuk | Contoh |
|---|---|---|
UserPromptSubmit | Sebelum prompt pengguna masuk ke Claude | Menyimpan request, mendeteksi secret, menambahkan konteks ringan |
PreToolUse | Tepat sebelum tool berjalan | Memblokir Bash command berbahaya atau operasi produksi |
PostToolUse | Setelah tool berhasil berjalan | Menjalankan formatter, lint, atau test terkait |
Stop | Saat Claude akan selesai menjawab | Mengecek konflik Git, menyimpan ringkasan, mengingatkan verifikasi |
Gunakan PreToolUse jika aksi tidak boleh terjadi. Gunakan PostToolUse jika aksi sudah terjadi dan perlu dirapikan atau diverifikasi. Gunakan UserPromptSubmit untuk memahami kualitas request. Gunakan Stop agar sesi tidak berakhir dengan masalah yang jelas.
Aturan bersama biasanya disimpan di .claude/settings.json. Eksperimen pribadi lebih aman di .claude/settings.local.json, supaya tidak ikut masuk repository. Dalam tim, tulis di README hook mana yang memblokir, hook mana yang hanya logging, dan siapa yang memeliharanya.
Konfigurasi minimum yang bisa disalin
Konfigurasi berikut menyimpan prompt, memblokir Bash berbahaya, menjalankan quality check setelah edit, dan menyimpan ringkasan saat selesai.
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/log-prompt.mjs"
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/block-dangerous-command.mjs"
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/run-quality-checks.mjs",
"timeout": 120
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/stop-summary.mjs"
}
]
}
]
}
}
Detail pentingnya adalah array hooks yang bersarang. Struktur modern berisi event, group dengan matcher jika perlu, lalu handler seperti type: "command". Contoh lama yang menaruh command langsung di samping matcher masih bisa ditemukan, tetapi bukan pola yang sebaiknya dipakai hari ini.
Use case 1: blokir command berbahaya dengan PreToolUse
Use case pertama adalah keamanan command. Saat agent bekerja cepat, momen paling berbahaya bukan setelah command selesai, tetapi tepat sebelum command dijalankan. PreToolUse dapat membaca input Bash dan menolak aksi yang jelas berisiko.
Simpan sebagai .claude/hooks/block-dangerous-command.mjs.
import fs from "node:fs";
const input = JSON.parse(fs.readFileSync(0, "utf8") || "{}");
const command = String(input.tool_input?.command || "");
const denyPatterns = [
/rm\s+-rf\s+(\/|\*|\.|\$HOME)/i,
/cat\s+\.env(\.|$|\s)/i,
/printenv/i,
/aws\s+.*\s+delete-/i,
/gcloud\s+.*\s+delete/i,
/kubectl\s+delete\s+(namespace|deployment|secret)/i,
/DROP\s+DATABASE/i
];
const matched = denyPatterns.find((pattern) => pattern.test(command));
if (matched) {
console.log(JSON.stringify({
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: `Blocked by project hook: ${matched}`
}
}));
process.exit(0);
}
Script ini bukan produk security lengkap. Regex bisa kurang dan bisa diakali. Namun ia cukup berguna untuk mencegah kesalahan yang sering terjadi: membaca .env, menghapus folder besar, menghapus resource cloud, menghapus object Kubernetes, atau menjalankan SQL destruktif. Untuk produksi, kombinasikan dengan permission Claude Code, protected branch, CI, dan approval manusia.
Use case 2: simpan prompt dengan UserPromptSubmit
Use case kedua adalah observability untuk prompt. Banyak sesi Claude Code gagal bukan karena model lemah, tetapi karena request awal terlalu kabur: “fix ini”, “rapikan”, “buat lebih bagus”. Dengan log, kamu bisa melihat pola request mana yang menghasilkan pekerjaan rapi.
Simpan sebagai .claude/hooks/log-prompt.mjs.
import fs from "node:fs";
import path from "node:path";
const input = JSON.parse(fs.readFileSync(0, "utf8") || "{}");
const dir = path.join(process.cwd(), ".claude", "hook-logs");
fs.mkdirSync(dir, { recursive: true });
const record = {
time: new Date().toISOString(),
event: input.hook_event_name,
cwd: input.cwd,
prompt: input.prompt || input.user_prompt || ""
};
fs.appendFileSync(
path.join(dir, "prompts.jsonl"),
JSON.stringify(record) + "\n",
"utf8"
);
Simpan log ini secara lokal dulu. Prompt bisa berisi nama klien, URL internal, token yang tidak sengaja ditempel, atau konteks bisnis sensitif. Masukkan .claude/hook-logs/ ke .gitignore, lalu tentukan masa simpan, akses, dan pemiliknya.
Use case 3: jalankan format dan test setelah edit
Use case ketiga adalah workflow kualitas harian. Setelah Claude menulis atau mengedit file, jalankan formatter dan verifikasi kecil. Dengan begitu, kamu tidak perlu menulis “tolong format dan test” di setiap prompt.
Simpan sebagai .claude/hooks/run-quality-checks.mjs.
import fs from "node:fs";
import { execFileSync } from "node:child_process";
const input = JSON.parse(fs.readFileSync(0, "utf8") || "{}");
const filePath = String(input.tool_input?.file_path || "");
const isSourceFile = /\.(js|jsx|ts|tsx|css|md|mdx|json)$/.test(filePath);
if (!isSourceFile) process.exit(0);
const run = (cmd, args) => {
try {
return execFileSync(cmd, args, {
cwd: process.cwd(),
encoding: "utf8",
stdio: ["ignore", "pipe", "pipe"]
});
} catch (error) {
return String(error.stdout || "") + String(error.stderr || "");
}
};
const messages = [];
messages.push(run("npx", ["prettier", "--write", filePath]));
if (/\.(js|jsx|ts|tsx)$/.test(filePath)) {
messages.push(run("npm", ["test", "--", "--runInBand"]));
}
console.log(JSON.stringify({
hookSpecificOutput: {
hookEventName: "PostToolUse",
additionalContext: messages.join("\n").slice(-4000)
}
}));
Untuk monorepo besar, jangan jalankan seluruh test suite setiap kali ada file ditulis. Mulai dari format, tambah test yang relevan, lalu pindahkan check berat ke async Hook atau CI. Batasi juga output yang dikembalikan ke Claude agar konteks tidak penuh log.
Use case 4: cek sesi dengan Stop
Stop berjalan saat Claude akan menyelesaikan jawaban. Cocok untuk menyimpan ringkasan atau memblokir kondisi yang jelas belum selesai, misalnya konflik Git.
import fs from "node:fs";
import { execFileSync } from "node:child_process";
const input = JSON.parse(fs.readFileSync(0, "utf8") || "{}");
if (input.stop_hook_active) {
process.exit(0);
}
let status = "";
try {
status = execFileSync("git", ["status", "--short"], {
cwd: process.cwd(),
encoding: "utf8"
});
} catch {
process.exit(0);
}
if (status.includes("UU ")) {
console.error("Git conflict remains. Resolve conflicts before finishing.");
process.exit(2);
}
fs.mkdirSync(".claude/hook-logs", { recursive: true });
fs.appendFileSync(
".claude/hook-logs/stop.jsonl",
JSON.stringify({
time: new Date().toISOString(),
lastAssistantMessage: input.last_assistant_message || "",
gitStatus: status.slice(0, 2000)
}) + "\n"
);
Hati-hati dengan Stop. Jika terlalu banyak kondisi yang memblokir, agent bisa terasa seperti tidak bisa selesai. Periksa stop_hook_active, buat kondisi sempit, dan mulai dari logging sebelum blocking.
Pitfall: kesalahan umum dan cara menghindarinya
Pitfall pertama adalah menganggap Hooks sebagai pengganti permission. Command hook berjalan dengan izin user sistem kamu. Jika script salah, ia bisa membaca secret atau menghapus file. Validasi input, cek path, hindari .env dan .git, serta tangani path traversal.
Pitfall kedua adalah menjalankan terlalu banyak tugas secara sinkron. Format satu file masih wajar. Build, full test, browser test, dan deploy setelah setiap edit biasanya terlalu berat. Check cepat taruh di PostToolUse; check lambat pindahkan ke async atau CI.
Pitfall ketiga adalah menyimpan log tanpa kebijakan. Log membantu debug, tetapi bisa menyimpan informasi sensitif. Tentukan lokasi, retensi, akses, dan aturan Git sebelum dipakai tim.
Pitfall keempat adalah salah memahami matcher. matcher: "Bash" hanya mengirim event Bash ke handler. Keputusan aman atau tidak tetap harus dibuat di dalam script dengan membaca command lengkap.
Catatan verifikasi ala Masa
Saat dicoba, peningkatan terbesar datang dari mengembalikan hasil format dan test ke Claude melalui additionalContext. Claude bisa memperbaiki langkah berikutnya tanpa manusia menyalin log ke chat. Blokir command berbahaya juga berguna, bukan karena sempurna, tetapi karena menghentikan kesalahan jelas di momen yang tepat.
Untuk tim yang baru mulai, saya akan menerapkannya bertahap: satu minggu log prompt, lalu format setelah edit, lalu daftar kecil Bash yang dilarang. Urutan ini membuat workflow terasa membantu, bukan mengganggu.
Jika ingin merapikan permission, CLAUDE.md, Hooks, dan review workflow bersama tim, lihat halaman Claude Code training. Untuk developer solo, pola yang sama bisa dijadikan checklist Gumroad untuk memulai proyek baru dengan setup yang konsisten.
Ringkasan
Claude Code Hooks adalah guardrail praktis. Gunakan UserPromptSubmit untuk memahami request, PreToolUse untuk memblokir aksi berisiko, PostToolUse untuk memverifikasi perubahan, dan Stop agar sesi tidak berakhir dengan masalah jelas.
Mulai dari kecil. Hook sederhana yang tetap aktif lebih bernilai daripada automasi besar yang dimatikan setelah dua hari.
PDF gratis: cheatsheet Claude Code
Masukkan email dan unduh satu halaman berisi command, kebiasaan review, dan workflow aman.
Kami menjaga datamu dan tidak mengirim spam.
Tentang penulis
Masa
Engineer yang berfokus pada workflow Claude Code praktis dan adopsi tim.
Artikel terkait
Permission receipt Claude Code: mencatat scope, bukti, dan rollback
Pola permission receipt untuk Claude Code: aksi yang diizinkan, batas approval, command verifikasi, rollback, dan cek CTA revenue.
Agent Harness Aman untuk Claude Code dan Codex: Permission, Verifikasi, dan Rollback
Rancang Agent Harness praktis untuk Claude Code dan Codex dengan policy, plan, verification, dan recovery layer.
Subagent Claude Code: panduan praktis untuk delegasi artikel dan kode
Panduan subagent Claude Code untuk membagi pekerjaan artikel dan kode: aturan delegasi, prompt, risiko, dan checklist.