Claude Code hooks adalah perintah shell yang didefinisikan pengguna yang dieksekusi pada berbagai titik dalam siklus hidup Claude Code. Hooks menyediakan kontrol deterministik atas perilaku Claude Code, memastikan tindakan tertentu selalu terjadi daripada mengandalkan LLM untuk memilih menjalankannya.

Untuk dokumentasi referensi tentang hooks, lihat Referensi Hooks.

Contoh kasus penggunaan untuk hooks meliputi:

  • Notifikasi: Sesuaikan cara Anda mendapatkan notifikasi ketika Claude Code menunggu input atau izin Anda untuk menjalankan sesuatu.
  • Pemformatan otomatis: Jalankan prettier pada file .ts, gofmt pada file .go, dll. setelah setiap pengeditan file.
  • Logging: Lacak dan hitung semua perintah yang dieksekusi untuk kepatuhan atau debugging.
  • Umpan balik: Berikan umpan balik otomatis ketika Claude Code menghasilkan kode yang tidak mengikuti konvensi codebase Anda.
  • Izin kustom: Blokir modifikasi pada file produksi atau direktori sensitif.

Dengan mengkodekan aturan-aturan ini sebagai hooks daripada instruksi prompting, Anda mengubah saran menjadi kode tingkat aplikasi yang dieksekusi setiap kali diharapkan untuk berjalan.

Anda harus mempertimbangkan implikasi keamanan dari hooks saat menambahkannya, karena hooks berjalan secara otomatis selama loop agen dengan kredensial lingkungan Anda saat ini. Misalnya, kode hooks yang berbahaya dapat mengeksfiltrasikan data Anda. Selalu tinjau implementasi hooks Anda sebelum mendaftarkannya.

Untuk praktik keamanan terbaik lengkap, lihat Pertimbangan Keamanan dalam dokumentasi referensi hooks.

Ikhtisar Event Hook

Claude Code menyediakan beberapa event hook yang berjalan pada titik-titik berbeda dalam alur kerja:

  • PreToolUse: Berjalan sebelum panggilan tool (dapat memblokir mereka)
  • PostToolUse: Berjalan setelah panggilan tool selesai
  • UserPromptSubmit: Berjalan ketika pengguna mengirimkan prompt, sebelum Claude memprosesnya
  • Notification: Berjalan ketika Claude Code mengirim notifikasi
  • Stop: Berjalan ketika Claude Code selesai merespons
  • SubagentStop: Berjalan ketika tugas subagen selesai
  • PreCompact: Berjalan sebelum Claude Code akan menjalankan operasi compact
  • SessionStart: Berjalan ketika Claude Code memulai sesi baru atau melanjutkan sesi yang ada
  • SessionEnd: Berjalan ketika sesi Claude Code berakhir

Setiap event menerima data yang berbeda dan dapat mengontrol perilaku Claude dengan cara yang berbeda.

Quickstart

Dalam quickstart ini, Anda akan menambahkan hook yang mencatat perintah shell yang dijalankan Claude Code.

Prasyarat

Instal jq untuk pemrosesan JSON di command line.

Langkah 1: Buka konfigurasi hooks

Jalankan slash command /hooks dan pilih event hook PreToolUse.

Hook PreToolUse berjalan sebelum panggilan tool dan dapat memblokir mereka sambil memberikan umpan balik Claude tentang apa yang harus dilakukan secara berbeda.

Langkah 2: Tambahkan matcher

Pilih + Add new matcher… untuk menjalankan hook Anda hanya pada panggilan tool Bash.

Ketik Bash untuk matcher.

Anda dapat menggunakan * untuk mencocokkan semua tool.

Langkah 3: Tambahkan hook

Pilih + Add new hook… dan masukkan perintah ini:

jq -r '"\(.tool_input.command) - \(.tool_input.description // "No description")"' >> ~/.claude/bash-command-log.txt

Langkah 4: Simpan konfigurasi Anda

Untuk lokasi penyimpanan, pilih User settings karena Anda mencatat ke direktori home Anda. Hook ini kemudian akan berlaku untuk semua proyek, bukan hanya proyek Anda saat ini.

Kemudian tekan Esc sampai Anda kembali ke REPL. Hook Anda sekarang terdaftar!

Langkah 5: Verifikasi hook Anda

Jalankan /hooks lagi atau periksa ~/.claude/settings.json untuk melihat konfigurasi Anda:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '\"\\(.tool_input.command) - \\(.tool_input.description // \"No description\")\"' >> ~/.claude/bash-command-log.txt"
          }
        ]
      }
    ]
  }
}

Langkah 6: Uji hook Anda

Minta Claude untuk menjalankan perintah sederhana seperti ls dan periksa file log Anda:

cat ~/.claude/bash-command-log.txt

Anda harus melihat entri seperti:

ls - Lists files and directories

Contoh Lainnya

Untuk implementasi contoh lengkap, lihat contoh validator perintah bash dalam codebase publik kami.

Hook Pemformatan Kode

Secara otomatis memformat file TypeScript setelah pengeditan:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|MultiEdit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | { read file_path; if echo \"$file_path\" | grep -q '\\.ts$'; then npx prettier --write \"$file_path\"; fi; }"
          }
        ]
      }
    ]
  }
}

Hook Pemformatan Markdown

Secara otomatis memperbaiki tag bahasa yang hilang dan masalah pemformatan dalam file markdown:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|MultiEdit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/markdown_formatter.py"
          }
        ]
      }
    ]
  }
}

Buat .claude/hooks/markdown_formatter.py dengan konten ini:

#!/usr/bin/env python3
"""
Markdown formatter for Claude Code output.
Fixes missing language tags and spacing issues while preserving code content.
"""
import json
import sys
import re
import os

def detect_language(code):
    """Best-effort language detection from code content."""
    s = code.strip()
    
    # JSON detection
    if re.search(r'^\s*[{\[]', s):
        try:
            json.loads(s)
            return 'json'
        except:
            pass
    
    # Python detection
    if re.search(r'^\s*def\s+\w+\s*\(', s, re.M) or \
       re.search(r'^\s*(import|from)\s+\w+', s, re.M):
        return 'python'
    
    # JavaScript detection  
    if re.search(r'\b(function\s+\w+\s*\(|const\s+\w+\s*=)', s) or \
       re.search(r'=>|console\.(log|error)', s):
        return 'javascript'
    
    # Bash detection
    if re.search(r'^#!.*\b(bash|sh)\b', s, re.M) or \
       re.search(r'\b(if|then|fi|for|in|do|done)\b', s):
        return 'bash'
    
    # SQL detection
    if re.search(r'\b(SELECT|INSERT|UPDATE|DELETE|CREATE)\s+', s, re.I):
        return 'sql'
        
    return 'text'

def format_markdown(content):
    """Format markdown content with language detection."""
    # Fix unlabeled code fences
    def add_lang_to_fence(match):
        indent, info, body, closing = match.groups()
        if not info.strip():
            lang = detect_language(body)
            return f"{indent}```{lang}\n{body}{closing}\n"
        return match.group(0)
    
    fence_pattern = r'(?ms)^([ \t]{0,3})```([^\n]*)\n(.*?)(\n\1```)\s*$'
    content = re.sub(fence_pattern, add_lang_to_fence, content)
    
    # Fix excessive blank lines (only outside code fences)
    content = re.sub(r'\n{3,}', '\n\n', content)
    
    return content.rstrip() + '\n'

# Main execution
try:
    input_data = json.load(sys.stdin)
    file_path = input_data.get('tool_input', {}).get('file_path', '')
    
    if not file_path.endswith(('.md', '.mdx')):
        sys.exit(0)  # Not a markdown file
    
    if os.path.exists(file_path):
        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()
        
        formatted = format_markdown(content)
        
        if formatted != content:
            with open(file_path, 'w', encoding='utf-8') as f:
                f.write(formatted)
            print(f"✓ Fixed markdown formatting in {file_path}")
    
except Exception as e:
    print(f"Error formatting markdown: {e}", file=sys.stderr)
    sys.exit(1)

Buat script dapat dieksekusi:

chmod +x .claude/hooks/markdown_formatter.py

Hook ini secara otomatis:

  • Mendeteksi bahasa pemrograman dalam blok kode yang tidak berlabel
  • Menambahkan tag bahasa yang sesuai untuk syntax highlighting
  • Memperbaiki baris kosong berlebihan sambil mempertahankan konten kode
  • Hanya memproses file markdown (.md, .mdx)

Hook Notifikasi Kustom

Dapatkan notifikasi desktop ketika Claude membutuhkan input:

{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "notify-send 'Claude Code' 'Awaiting your input'"
          }
        ]
      }
    ]
  }
}

Hook Perlindungan File

Blokir pengeditan pada file sensitif:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|MultiEdit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "python3 -c \"import json, sys; data=json.load(sys.stdin); path=data.get('tool_input',{}).get('file_path',''); sys.exit(2 if any(p in path for p in ['.env', 'package-lock.json', '.git/']) else 0)\""
          }
        ]
      }
    ]
  }
}

Pelajari lebih lanjut

  • Untuk dokumentasi referensi tentang hooks, lihat Referensi Hooks.
  • Untuk praktik keamanan terbaik yang komprehensif dan panduan keselamatan, lihat Pertimbangan Keamanan dalam dokumentasi referensi hooks.
  • Untuk langkah-langkah troubleshooting dan teknik debugging, lihat Debugging dalam dokumentasi referensi hooks.