Hook Cursor: panduan lengkap, dan mengapa hook terkadang tidak terpicu

Hook Cursor memungkinkan sebuah skrip mengawasi atau memblokir apa yang dilakukan agen: setiap perintah shell, pemanggilan MCP, pembacaan file, dan pengeditan. Hook sangat ampuh, tetapi saat gagal sering kali tidak ada tanda apa pun. Inilah semua yang kami pelajari saat memasangnya untuk penggunaan sungguhan.

Oleh Aslan, tim Pet Island · Diperbarui 26 Okt 2026 · 7 menit baca

JAWABAN SINGKAT

Letakkan hooks.json dengan "version": 1 di ~/.cursor/ (semua proyek) atau .cursor/ di dalam repo, arahkan setiap event ke sebuah perintah, dan cetak JSON ke stdout. Gunakan beforeShellExecution dan beforeMCPExecution untuk allow, deny, atau ask, dan setel failClosed: true jika hook yang rusak harus memblokir alih-alih meloloskan perintah. Saat hook tampak diabaikan, buka dulu output channel Hooks: sebagian besar masalah berasal dari path, workspace yang tidak tepercaya, JSON yang tidak valid, atau event yang belum dikirim oleh Cursor CLI.

Apa itu hook Cursor

Hook adalah perintah yang dijalankan Cursor pada titik tertentu dalam loop agen. Cursor mengirim objek JSON yang menjelaskan apa yang akan terjadi ke input standar perintah tersebut, menunggu, lalu membaca jawaban JSON dari output standarnya. Sebagian hook hanya mengamati (mencatat pengeditan, memformat file). Sebagian lainnya memutuskan: hook beforeShellExecution dapat membiarkan perintah berjalan, menghentikannya, atau menanyakannya kepada Anda terlebih dahulu.

Karena itu, hook adalah alat yang tepat untuk tiga pekerjaan: pengaman (jangan pernah menjalankan rm -rf atau git push --force tanpa manusia), otomatisasi (format atau lint setelah setiap pengeditan), dan visibilitas (mencatat atau meneruskan apa yang dilakukan agen agar Anda tahu kapan agen membutuhkan Anda).

Lokasi hooks.json

Cursor membaca hook dari empat tempat dan menjalankan semuanya. Setiap hook yang cocok dari setiap sumber dijalankan, dan Cursor menggabungkan jawabannya.

TingkatFileCatatan
Pengguna~/.cursor/hooks.jsonBerlaku untuk setiap proyek. Perintah relatif diselesaikan dari ~/.cursor/.
Proyek<project>/.cursor/hooks.jsonDi-commit ke repo. Hanya berjalan di workspace tepercaya. Perintah relatif diselesaikan dari root proyek.
TimDasbor web CursorHanya untuk Enterprise, disinkronkan ke setiap anggota.
EnterpriseC:\ProgramData\Cursor\hooks.json (Windows), /Library/Application Support/Cursor/hooks.json (macOS), /etc/cursor/hooks.json (Linux, WSL)Dikelola oleh tim IT.

Jika jawaban-jawabannya berbeda, yang paling ketat yang menang: deny dari sumber mana pun mengalahkan ask, dan ask mengalahkan allow. File terkecil yang berfungsi terlihat seperti ini (diambil dari contoh di dokumentasi Cursor):

~/.cursor/hooks.jsonSalin
{
"version": 1,
"hooks": {
"afterFileEdit": [{ "command": "./hooks/format.sh" }]
}
}

version harus bernilai 1. Cursor memantau file ini dan memuatnya ulang saat Anda menyimpan. Jika perubahan tidak berlaku, restart Cursor. Langkah itu saja sudah menyelesaikan cukup banyak laporan di forum.

Event yang bisa Anda kaitkan dengan hook

Daftar terbaru dari dokumentasi Cursor, dikelompokkan berdasarkan fungsinya:

KelompokEventBisa memblokir?
Shell dan MCPbeforeShellExecution, afterShellExecution, beforeMCPExecution, afterMCPExecutionDua hook before…: allow, deny, atau ask
Alat apa punpreToolUse, postToolUse, postToolUseFailurepreToolUse: allow atau deny (ask saat ini tidak ditegakkan)
FilebeforeReadFile, afterFileEditbeforeReadFile: allow atau deny
PromptbeforeSubmitPromptYa, dengan continue: false
Loop agenstop, afterAgentResponse, afterAgentThought, preCompactTidak (stop dapat mengirim pesan lanjutan)
SubagensubagentStart, subagentStopsubagentStart: allow atau deny (ask dihitung sebagai deny)
Sesi dan aplikasisessionStart, sessionEnd, workspaceOpenTidak
Penyelesaian TabbeforeTabFileRead, afterTabFileEditbeforeTabFileRead: allow atau deny

Setiap event menerima beberapa kolom umum (conversation_id, generation_id, model, hook_event_name, cursor_version, workspace_roots) ditambah kolomnya sendiri. beforeShellExecution mendapatkan command lengkap dan cwd-nya; stop mendapatkan status berupa completed, aborted, atau error.

Allow, deny, dan ask

Hook yang mengambil keputusan mencetak satu objek JSON. Untuk hook shell, bentuknya seperti ini:

stdout dari hook beforeShellExecutionSalin
{
"permission": "ask",
"user_message": "This pushes to main. Run it?",
"agent_message": "The user wants to confirm pushes."
}
  • permission bernilai allow, deny, atau ask.
  • user_message adalah yang Anda lihat di Cursor.
  • agent_message adalah yang disampaikan kepada agen, agar agen bisa mengubah arah alih-alih mencoba ulang perintah yang sama.

Kode keluar sama pentingnya dengan JSON. Keluar dengan 0 berarti “gunakan JSON saya”. Keluar dengan 2 memblokir tindakan, sama seperti deny. Kode keluar lainnya dianggap sebagai hook yang gagal, dan tindakan tetap berjalan, kecuali Anda menyetel failClosed. Untuk hook izin, JSON yang tidak valid atau tidak sesuai skema akan memblokir tindakan.

Dokumentasi Cursor mencantumkan ask sebagai didukung untuk beforeShellExecution dan beforeMCPExecution. Pada Maret 2026, staf Cursor menulis di forum bahwa hook hanya menegakkan deny dan bahwa allow serta ask “basically ignored” (pada dasarnya diabaikan), terutama saat allowlist perintah atau sandbox aktif. Kami belum menemukan pengumuman perbaikannya. Jika sebuah pengaman harus bertahan, kembalikan deny, bukan ask, dan uji di versi Anda sendiri.

failClosed dan timeout

Setiap entri hook dapat membawa opsi di samping command:

.cursor/hooks.jsonSalin
{
"version": 1,
"hooks": {
"beforeShellExecution": [
{
"command": "./.cursor/hooks/guard.sh",
"timeout": 30,
"failClosed": true
}
]
}
}
  • failClosed: true mengubah crash, timeout, kode keluar bukan nol, atau output kosong menjadi pemblokiran. Default-nya false: hook penjaga yang rusak diam-diam meloloskan semuanya. Untuk hook keamanan, Anda hampir selalu menginginkan true.
  • timeout dalam satuan detik. Sisakan waktu yang cukup jika hook Anda menunggu manusia: orang yang membaca diff butuh lebih dari lima detik.
  • matcher memfilter kapan hook berjalan. Untuk hook shell, matcher dicocokkan dengan string perintah lengkap; untuk hook alat, dengan jenis alat, seperti Shell, Read, Write, atau MCP:<tool_name>.

Ada konsekuensinya. Pada Juli 2026, seorang pengguna macOS mengalami “MainThreadShellExec not initialized”: host shell milik Cursor sendiri belum siap, dan karena hook-nya fail-closed, shell agen terblokir. Staf Cursor mengatakan perbaikannya sudah dirilis dan merekomendasikan tetap memakai failClosed: true. Jika Anda melihat error itu di build lama, “Developer: Reload Window” adalah solusi sementaranya.

Hook di Windows

Di Windows, aplikasi desktop Cursor menjalankan perintah hook melalui PowerShell dan mengirimkan JSON lewat pipe. Skrip PowerShell membacanya dari $input; program lain membaca input standar seperti biasa. Ada tiga hal yang sering menjebak:

  1. Skrip Bash tidak bisa langsung berjalan. guard.sh dari rekan tim pengguna macOS akan gagal di PowerShell. Gunakan skrip .ps1, program yang dikompilasi, atau panggil interpreter Anda secara eksplisit (python .cursor/hooks/guard.py). Sebuah thread forum dari Januari 2026 menunjukkan konfigurasi Git Bash yang gagal dengan syntax error near unexpected token '[Convert]::FromBase64String', yaitu kode PowerShell yang sampai ke bash.
  2. Execution policy. Jika PowerShell menolak menjalankan skrip, jalankan skrip dengan powershell -NoProfile -ExecutionPolicy Bypass -File …, cetak JSON-nya, dan akhiri dengan exit 0.
  3. Program GUI mengembalikan kontrol terlalu cepat. Masalah yang satu ini menghabiskan waktu kami seharian. Jika hook Anda adalah program Windows yang dibangun untuk subsistem GUI, PowerShell menjalankannya lalu lanjut tanpa menunggu. Cursor membaca output kosong, sehingga hook tampak tidak melakukan apa-apa (atau, dengan failClosed, memblokir semuanya). Bangun hook sebagai program konsol, atau bungkus agar PowerShell menunggu hingga program selesai.

Hook tingkat proyek juga memerlukan workspace tepercaya. Seorang staf Cursor mencantumkan apa yang perlu dicek saat hook tidak melakukan apa-apa: baris log Hooks “Hook N produced no output”, Settings → Hooks yang menunjukkan workspace sebagai tepercaya, dan error seperti spawn, ENOENT, EPERM, atau ExecutionPolicy di konsol.

Hook di Cursor CLI

Cursor CLI (cursor-agent) membaca ~/.cursor/hooks.json dan .cursor/hooks.json yang sama, tetapi tidak pernah mengirim semua event yang dikirim editor. Pada Januari 2026, hanya dua hook shell yang terpicu. Pada April, staf Cursor mengonfirmasi bahwa beforeShellExecution, afterShellExecution, afterFileEdit, postToolUse, stop, dan sessionStart berfungsi di CLI, sementara afterAgentResponse dan afterAgentThought masih belum (dikonfirmasi lagi pada Mei). Untuk event yang tidak ada di daftar itu, uji dulu sebelum Anda mengandalkannya.

Cloud agent bahkan lebih ketat: hook tingkat pengguna dari ~/.cursor/hooks.json sama sekali tidak berjalan di sana.

Saat hook tidak terpicu: daftar periksa

  1. Buka output channel Hooks (View → Output → Hooks) atau tab Hooks di Customize. Di sana terlihat hook mana yang dimuat, setiap eksekusi, dan error.
  2. Cek file JSON-nya. "version": 1 ada, nama event dieja persis (peka huruf besar-kecil), JSON valid.
  3. Cek path-nya. Perintah relatif diselesaikan dari root proyek untuk hook proyek dan dari ~/.cursor/ untuk hook pengguna.
  4. Percayai workspace-nya. Hook proyek tidak berjalan di folder yang tidak tepercaya.
  5. Jalankan hook secara manual. Kirim contoh JSON lewat pipe ke hook dan lihat stdout-nya. Apa pun selain satu objek JSON (echo yang nyasar, sebuah peringatan) akan merusak parsing.
  6. Restart Cursor. Menyimpan file memang memuatnya ulang, tetapi beberapa laporan di forum baru terselesaikan dengan restart penuh.
  7. Ketahui keterbatasannya. ask dan allow dilaporkan diabaikan saat ada allowlist dan sandbox; subagentStart/subagentStop dilaporkan tidak terpicu di beberapa versi; CLI melewatkan beberapa event. Commit dari panel Source Control bawaan tidak dicegat: tidak ada event hook pre-commit.

Hook, auto-run, dan Auto-review

Hook terpisah dari pengaturan persetujuan milik Cursor sendiri (Settings → Agents → Approvals & Execution). Auto-run dan Auto-review menentukan apakah Cursor bertanya kepada Anda di panelnya; hook Anda menambahkan keputusannya sendiri di atasnya. Itulah sebabnya laporan “hook saya bilang ask, tetapi perintahnya langsung berjalan” begitu umum: jalur izin lain sudah mengizinkannya.

Satu hal lagi yang kami pelajari dengan cara yang sulit: dengan Auto-review, Cursor dapat menanyakan beberapa perintah di jendelanya sendiri. Hook tidak pernah melihat pertanyaan itu. Pertanyaan tersebut terjadi di dalam Cursor, bukan di pipeline hook.

Peran Pet Island

Jika yang Anda inginkan dari hook adalah “tunjukkan setiap perintah berisiko dan biarkan saya memutuskan tanpa berpindah jendela”, itulah yang dilakukan Pet Island dengan Cursor. Pet Island memasang hook untuk Anda (beforeShellExecution dan beforeMCPExecution, dengan failClosed aktif agar helper yang mati tidak pernah meloloskan perintah) dan menempatkan setiap permintaan di sebuah island kecil di bagian atas layar Anda beserta perintah lengkapnya. Anda mengizinkan atau menolaknya di sana; agen Cursor menunggu.

Perintah dan pengeditan file dari editor Cursor bisa ditangani dari island. Pertanyaan dan rencana tampil di island, dan Anda menjawabnya di Cursor. Di Cursor CLI, perintah bisa ditangani dari island; event lainnya bergantung pada apa yang dikirim CLI. Menghapus instalasi hanya menghapus entri yang ditambahkan Pet Island; hook Anda sendiri tetap ada.

FAQ

Apakah hook Cursor berfungsi di Windows?

Ya. Aplikasi desktop menjalankannya melalui PowerShell dan meneruskan JSON lewat input standar ($input di skrip PowerShell). Skrip Bash yang ditulis untuk macOS memerlukan versi PowerShell atau Python, dan program subsistem GUI harus dibungkus agar PowerShell menunggunya.

Mengapa hook saya mengembalikan ask tetapi perintahnya tetap berjalan?

Staf Cursor mengatakan pada Maret 2026 bahwa hook hanya menegakkan deny secara andal; allow dan ask bisa ditimpa oleh allowlist atau sandbox. Gunakan deny untuk apa pun yang tidak boleh berjalan, dan cek output channel Hooks untuk melihat apa yang sebenarnya dikembalikan hook Anda.

Apa fungsi failClosed?

Dengan failClosed disetel ke true, crash, timeout, kode keluar bukan nol, atau output kosong akan memblokir tindakan. Tanpanya, hook yang rusak meloloskan tindakan.

Di mana saya bisa melihat error hook?

Di output channel Hooks (View → Output → Hooks) dan tab Hooks di Customize.

Apakah hook berfungsi di Cursor CLI?

Sebagian. CLI membaca file hooks.json yang sama. Per Mei 2026, staf Cursor mengonfirmasi hook shell, afterFileEdit, postToolUse, stop, dan sessionStart, tetapi tidak afterAgentResponse atau afterAgentThought.

Bisakah hook menghentikan git commit dari panel Source Control?

Tidak. Cursor tidak memiliki event hook pre-commit, dan commit yang dibuat melalui UI Source Control bawaan tidak dicegat. Gunakan hook pre-commit git biasa untuk itu.

Sumber

Setiap pengaturan dan perilaku di halaman ini telah dicocokkan dengan halaman-halaman berikut pada 26 Oktober 2026. Agen berubah dengan cepat; jika ada yang tidak lagi sesuai, halaman resmi yang berlaku.

BACA JUGA

Jawab setiap agen dari bagian atas layar Anda.

Windows dan Mac · Gratis 7 hari, lalu $8.99 sekali bayar · $1 dari setiap penjualan memberi makan hewan jalanan

Coba Pet Island gratis