Advanced (Diperbarui: 1/6/2026)

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.

Panduan Claude Code Hooks: cek aman sebelum dan sesudah kerja

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.

EventCocok untukContoh
UserPromptSubmitSebelum prompt pengguna masuk ke ClaudeMenyimpan request, mendeteksi secret, menambahkan konteks ringan
PreToolUseTepat sebelum tool berjalanMemblokir Bash command berbahaya atau operasi produksi
PostToolUseSetelah tool berhasil berjalanMenjalankan formatter, lint, atau test terkait
StopSaat Claude akan selesai menjawabMengecek 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.

#Claude Code #Hooks #automation #security #testing
Gratis

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.

Masa

Tentang penulis

Masa

Engineer yang berfokus pada workflow Claude Code praktis dan adopsi tim.