Hook
Hook memungkinkan Anda mengamati, mengontrol, dan memperluas Agent Loop dengan skrip kustom. Definisikan hook dalam file hooks.json di tingkat proyek atau pengguna, atau instal melalui plugin dari Sesuaikan. Hook adalah proses terpisah yang berkomunikasi dua arah melalui stdio menggunakan JSON. Hook berjalan sebelum atau sesudah tahap tertentu dalam Agent Loop dan dapat mengamati, memblokir, atau mengubah perilaku.
Dengan hook, Anda dapat:
- Menjalankan formatter setelah pengeditan
- Menambahkan analitik untuk peristiwa
- Memindai PII atau secret
- Membatasi operasi berisiko (misalnya, penulisan SQL)
- Mengontrol eksekusi subagent (tool Task)
- Menyisipkan konteks saat sesi dimulai
Mencari integrasi siap pakai? Lihat Integrasi Mitra untuk solusi keamanan, tata kelola, dan manajemen secret dari partner ekosistem kami.
Cursor mendukung pemuatan hook dari alat pihak ketiga seperti Claude Code. Lihat Hook Pihak Ketiga untuk detail kompatibilitas dan konfigurasi.
Kategori hook
Hook dibagi menjadi tiga kategori berdasarkan pemicunya:
Hook agent (Cmd+K/Agent Chat) berjalan selama sesi agent:
sessionStart/sessionEnd- Manajemen siklus hidup sesipreToolUse/postToolUse/postToolUseFailure- Hook penggunaan tool umum (berjalan untuk semua tool)subagentStart/subagentStop- Siklus hidup subagent (tool Task)beforeShellExecution/afterShellExecution- Mengontrol perintah shellbeforeMCPExecution/afterMCPExecution- Mengontrol penggunaan tool MCPbeforeReadFile/afterFileEdit- Mengontrol akses dan pengeditan filebeforeSubmitPrompt- Memvalidasi prompt sebelum dikirimpreCompact- Memantau pemadatan jendela konteksstop- Menangani selesainya agentafterAgentResponse/afterAgentThought- Melacak respons agent
Hook Tab (inline completions) berjalan untuk operasi Tab otonom:
beforeTabFileRead- Mengontrol akses file untuk Tab completionafterTabFileEdit- Memproses pengeditan Tab setelahnya
Hook siklus hidup aplikasi berjalan di luar sesi agent mana pun:
workspaceOpen- Berjalan saat Cursor membuka workspace dan setiap kali folder workspace berubah. Dapat mengembalikan path plugin tambahan untuk dimuat di workspace saat ini.
Antarmuka hook yang terpisah ini memungkinkan Anda menerapkan kebijakan berbeda untuk operasi Tab otonom, operasi Agent yang diarahkan pengguna, dan startup workspace.
Dukungan agen cloud
Agen cloud menjalankan hook berbasis perintah dari repositori Anda. Jika hook didefinisikan dalam .cursor/hooks.json di direktori root proyek Anda, agen cloud akan mendeteksi dan menjalankannya saat bekerja.
Pada paket Enterprise, agen cloud juga menjalankan Team hooks dan hook yang dikelola perusahaan, yang diatur melalui dashboard web.
Agen cloud terkadang memulai giliran eksplorasi awal dalam lingkungan baca saja. Hook tidak dijalankan selama giliran tersebut. Hook mulai dijalankan setelah agen memiliki lingkungan yang dapat ditulisi.
Hook yang didukung
Hook berikut berjalan pada agen cloud:
| Hook | Didukung |
|---|---|
beforeShellExecution | Ya |
afterShellExecution | Ya |
beforeReadFile | Ya |
afterFileEdit | Ya |
preToolUse | Ya |
postToolUse | Ya |
postToolUseFailure | Ya |
subagentStart | Ya |
subagentStop | Ya |
beforeSubmitPrompt | Ya |
preCompact | Ya |
afterAgentResponse | Ya |
afterAgentThought | Ya |
stop | Ya |
Hook tidak tersedia di agen cloud
Beberapa hook tidak berlaku untuk agen cloud karena perbedaan lingkungan eksekusi:
| Hook | Alasan |
|---|---|
sessionStart | Ditunda karena agen cloud masih dapat dimulai di lingkungan baca saja. Hook tidak dimuat di sana, sehingga sessionStart cloud akan dipicu terlambat (setelah penulisan pertama), bukan pada awal sesi yang sebenarnya. |
sessionEnd | Agen cloud tidak memiliki batas sesi berdasarkan masa aktif Editor. sessionEnd terikat pada sesi IDE, bukan chat agen cloud. |
beforeMCPExecution / afterMCPExecution | Ditunda karena agen cloud masih dapat dimulai di lingkungan baca saja, tempat hook tidak dimuat dan waktu pemicu hook MCP tidak jelas. |
beforeTabFileRead / afterTabFileEdit | Tab completion adalah fitur IDE dan tidak berjalan di agen cloud. |
workspaceOpen | Ini adalah hook siklus hidup aplikasi IDE dan tidak berlaku untuk agen cloud. |
Sumber konfigurasi
Agen cloud memuat hooks dari sumber berikut:
- Hooks proyek (
.cursor/hooks.jsondi repo Anda): Dimuat dan dijalankan saat agen cloud bekerja. - Team hooks (Enterprise): Didistribusikan melalui Dashboard dan dijalankan di agen cloud.
- Hooks Enterprise (Enterprise): Hooks terkelola di seluruh sistem yang dijalankan di agen cloud.
Hooks tingkat pengguna (~/.cursor/hooks.json) tidak tersedia di agen cloud. VM agen cloud tidak dapat mengakses konfigurasi direktori beranda lokal Anda.
Batasan jenis eksekusi
Agen cloud hanya menjalankan hook berbasis perintah. Hook berbasis prompt memerlukan integrasi autentikasi antara hook dan Agent Loop, yang tidak tersedia di lingkungan eksekusi cloud.
Mulai Cepat
Buat file hooks.json. Anda dapat membuatnya di tingkat proyek (<project>/.cursor/hooks.json) atau di direktori beranda (~/.cursor/hooks.json). Hooks tingkat proyek hanya berlaku untuk proyek tersebut, sedangkan hooks di direktori beranda berlaku secara global.
Untuk hooks tingkat pengguna yang berlaku secara global, buat ~/.cursor/hooks.json:
{ "version": 1, "hooks": { "afterFileEdit": [{ "command": "./hooks/format.sh" }] }}Buat skrip hook di ~/.cursor/hooks/format.sh:
#!/bin/bash# Baca input, lakukan sesuatu, lalu keluar dengan kode 0cat > /dev/nullexit 0Jadikan skrip dapat dieksekusi:
chmod +x ~/.cursor/hooks/format.shCursor memantau file konfigurasi hooks dan memuat ulang secara otomatis. Hook Anda berjalan setelah setiap pengeditan file.
Jenis Hook
Hook mendukung dua jenis eksekusi: berbasis perintah (default) dan berbasis prompt (dievaluasi LLM).
Hook Berbasis Perintah
Hook perintah menjalankan skrip shell yang menerima input JSON melalui stdin dan menghasilkan output JSON melalui stdout.
{ "hooks": { "beforeShellExecution": [ { "command": "./scripts/approve-network.sh", "timeout": 30, "matcher": "curl|wget|nc" } ] }}Perilaku exit code:
- Exit code
0- Hook berhasil, gunakan output JSON - Exit code
2- Blokir action (setara dengan mengembalikanpermission: "deny") - Exit code lainnya - Hook gagal, action tetap dilanjutkan (secara default, gagal-terbuka)
Hook Berbasis Prompt
Hook berbasis prompt menggunakan LLM untuk mengevaluasi kondisi dalam bahasa alami. Hook ini berguna untuk menerapkan kebijakan tanpa perlu menulis skrip kustom.
{ "hooks": { "beforeShellExecution": [ { "type": "prompt", "prompt": "Does this command look safe to execute? Only allow read-only operations.", "timeout": 10 } ] }}Fitur:
- Menghasilkan respons terstruktur
{ ok: boolean, reason?: string } - Menggunakan model cepat untuk evaluasi singkat
- Placeholder
$ARGUMENTSotomatis diganti dengan JSON input hook - Jika
$ARGUMENTStidak ada, input hook otomatis ditambahkan - Field
modelopsional untuk mengganti model LLM default
Contoh
Contoh di bawah menggunakan path ./hooks/..., yang berfungsi untuk hook pengguna (~/.cursor/hooks.json), karena skrip dijalankan dari ~/.cursor/. Untuk hook proyek (<project>/.cursor/hooks.json), gunakan path .cursor/hooks/... karena skrip dijalankan dari root proyek.
{ "version": 1, "hooks": { "sessionStart": [ { "command": "./hooks/session-init.sh" } ], "sessionEnd": [ { "command": "./hooks/audit.sh" } ], "beforeShellExecution": [ { "command": "./hooks/audit.sh" }, { "command": "./hooks/block-git.sh" } ], "beforeMCPExecution": [ { "command": "./hooks/audit.sh" } ], "afterShellExecution": [ { "command": "./hooks/audit.sh" } ], "afterMCPExecution": [ { "command": "./hooks/audit.sh" } ], "afterFileEdit": [ { "command": "./hooks/audit.sh" } ], "beforeSubmitPrompt": [ { "command": "./hooks/audit.sh" } ], "preCompact": [ { "command": "./hooks/audit.sh" } ], "stop": [ { "command": "./hooks/audit.sh" } ], "beforeTabFileRead": [ { "command": "./hooks/redact-secrets-tab.sh" } ], "afterTabFileEdit": [ { "command": "./hooks/format-tab.sh" } ] }}Hook otomatisasi stop TypeScript
Pilih TypeScript jika Anda memerlukan JSON bertipe, I/O file persisten, dan panggilan HTTP dalam satu hook. Hook stop berbasis Bun ini melacak jumlah kegagalan per percakapan di disk, meneruskan telemetri terstruktur ke API internal, dan dapat menjadwalkan percobaan ulang secara otomatis jika agent gagal dua kali berturut-turut.
{ "version": 1, "hooks": { "stop": [ { "command": "bun run .cursor/hooks/track-stop.ts --stop" } ] }}Atur AGENT_TELEMETRY_URL ke endpoint internal yang akan menerima ringkasan run.
Hook pengaman manifes Python
Python sangat cocok saat Anda memerlukan pustaka parsing yang lengkap. Hook ini menggunakan pyyaml untuk memeriksa manifes Kubernetes sebelum kubectl apply dijalankan; Bash akan kesulitan mem-parsing YAML multi-dokumen dengan aman.
{ "version": 1, "hooks": { "beforeShellExecution": [ { "command": "python3 .cursor/hooks/kube_guard.py" } ] }}Instal PyYAML (misalnya, pip install pyyaml) di setiap lingkungan tempat skrip hook Anda dijalankan agar impor parser berhasil.
Integrasi Mitra
Kami bermitra dengan penyedia dalam ekosistem yang telah membangun dukungan hook untuk Cursor. Integrasi ini mencakup pemindaian keamanan, tata kelola, manajemen secret, dan lainnya.
Tata kelola dan visibilitas MCP
| Mitra | Deskripsi |
|---|---|
| MintMCP | Bangun inventaris lengkap server MCP, pantau pola penggunaan alat, dan pindai respons untuk mendeteksi data sensitif sebelum mencapai model AI. |
| Oasis Security | Terapkan kebijakan hak istimewa minimum pada tindakan agent AI dan pertahankan jejak audit lengkap di seluruh sistem perusahaan. |
| Runlayer | Bungkus alat MCP dan integrasikan dengan broker MCP mereka untuk kontrol dan visibilitas terpusat atas interaksi antara agent dan alat. |
Keamanan kode dan praktik terbaik
| Mitra | Deskripsi |
|---|---|
| Corridor | Dapatkan feedback real-time tentang implementasi kode dan keputusan desain keamanan saat kode sedang ditulis. |
| Semgrep | Secara otomatis memindai kode yang dihasilkan AI untuk mendeteksi kerentanan, dengan feedback real-time untuk membuat ulang kode hingga masalah keamanan selesai. |
Keamanan dependency
| Partner | Deskripsi |
|---|---|
| Endor Labs | Mencegat instalasi package dan memindai dependency berbahaya untuk mencegah serangan rantai pasokan sebelum mencapai codebase Anda. |
Keamanan dan keselamatan agent
| Partner | Deskripsi |
|---|---|
| Snyk | Tinjau tindakan agent secara real-time dengan Evo Agent Guard untuk mendeteksi dan mencegah masalah seperti prompt injection dan pemanggilan tool berbahaya. |
Manajemen secret
| Partner | Deskripsi |
|---|---|
| 1Password | Pastikan file lingkungan dari 1Password Environments ter-mount dengan benar sebelum perintah shell dijalankan, sehingga secret dapat diakses tepat saat dibutuhkan tanpa menulis kredensial ke disk. |
Untuk informasi selengkapnya tentang partner hooks kami, lihat postingan blog Hooks for security and platform teams.
Konfigurasi
Tentukan hook dalam file hooks.json. Konfigurasi dapat diterapkan di beberapa tingkat. Semua hook yang cocok dari setiap sumber akan dijalankan; jika respons saling bertentangan, sumber dengan prioritas lebih tinggi akan diutamakan saat penggabungan:
~/.cursor/├── hooks.json└── hooks/ ├── audit.sh └── block-git.sh- Enterprise (dikelola oleh MDM, berlaku di seluruh sistem):
- macOS:
/Library/Application Support/Cursor/hooks.json - Linux/WSL:
/etc/cursor/hooks.json - Windows:
C:\\ProgramData\\Cursor\\hooks.json
- macOS:
- Tim (didistribusikan melalui Cloud, hanya Enterprise):
- Dikonfigurasi di web dashboard dan otomatis disinkronkan ke semua anggota tim
- Proyek (khusus proyek):
<project-root>/.cursor/hooks.json- hook proyek dijalankan di workspace tepercaya mana pun dan disertakan dalam sistem kontrol versi bersama proyek Anda
- Pengguna (khusus pengguna):
~/.cursor/hooks.json
Urutan prioritas (tertinggi hingga terendah): Enterprise → Tim → Proyek → Pengguna
Objek hooks memetakan nama hook ke array definisi hook. Setiap definisi saat ini mendukung properti command, yang dapat berupa string shell, path absolut, atau path relatif. Direktori kerja bergantung pada sumber hook:
- hook proyek (
.cursor/hooks.jsondalam repositori): Dijalankan dari root proyek - hook pengguna (
~/.cursor/hooks.json): Dijalankan dari~/.cursor/ - hook Enterprise (config di seluruh sistem): Dijalankan dari direktori config perusahaan
- Team hooks (didistribusikan melalui cloud): Dijalankan dari direktori hooks yang dikelola
Untuk hook proyek, gunakan path seperti .cursor/hooks/script.sh (relatif terhadap root proyek), bukan ./hooks/script.sh (yang akan mencari <project>/hooks/script.sh).
File konfigurasi
Contoh ini menunjukkan file hooks tingkat pengguna (~/.cursor/hooks.json). Untuk hooks tingkat proyek, ubah path seperti ./hooks/script.sh menjadi .cursor/hooks/script.sh:
{ "version": 1, "hooks": { "sessionStart": [{ "command": "./session-init.sh" }], "sessionEnd": [{ "command": "./audit.sh" }], "preToolUse": [ { "command": "./hooks/validate-tool.sh", "matcher": "Shell|Read|Write" } ], "postToolUse": [{ "command": "./hooks/audit-tool.sh" }], "subagentStart": [{ "command": "./hooks/validate-subagent.sh" }], "subagentStop": [{ "command": "./hooks/audit-subagent.sh" }], "beforeShellExecution": [{ "command": "./script.sh" }], "afterShellExecution": [{ "command": "./script.sh" }], "afterMCPExecution": [{ "command": "./script.sh" }], "afterFileEdit": [{ "command": "./format.sh" }], "preCompact": [{ "command": "./audit.sh" }], "stop": [{ "command": "./audit.sh", "loop_limit": 10 }], "beforeTabFileRead": [{ "command": "./redact-secrets-tab.sh" }], "afterTabFileEdit": [{ "command": "./format-tab.sh" }], "workspaceOpen": [{ "command": "./register-workspace-plugins.sh" }] }}Hook agent (sessionStart, sessionEnd, preToolUse, postToolUse, postToolUseFailure, subagentStart, subagentStop, beforeShellExecution, afterShellExecution, beforeMCPExecution, afterMCPExecution, beforeReadFile, afterFileEdit, beforeSubmitPrompt, preCompact, stop, afterAgentResponse, afterAgentThought) berlaku untuk operasi Cmd+K dan Agent Chat. Hook Tab (beforeTabFileRead, afterTabFileEdit) khusus berlaku untuk Tab completion inline. Hook siklus hidup aplikasi (workspaceOpen) dipicu saat workspace dibuka dan ketika folder workspace berubah, terlepas dari sesi agent apa pun.
Opsi Konfigurasi Global
| Opsi | Jenis | Default | Deskripsi |
|---|---|---|---|
version | number | 1 | Versi skema konfigurasi |
Opsi Konfigurasi per Skrip
| Opsi | Jenis | Default | Deskripsi |
|---|---|---|---|
command | string | wajib | Path atau perintah skrip |
type | "command" | "prompt" | "command" |
timeout | number | default platform | Batas waktu eksekusi dalam detik |
loop_limit | number | null | 5 |
failClosed | boolean | false | Jika true, kegagalan hook (crash, batas waktu, JSON tidak valid) memblokir tindakan, bukan mengizinkannya. Berguna untuk hook yang sangat penting bagi keamanan. |
matcher | object | - | Kriteria filter untuk menentukan kapan hook dijalankan |
Konfigurasi Matcher
Matcher memungkinkan Anda memfilter kondisi kapan hook dijalankan. Field yang digunakan matcher bergantung pada hook:
{ "hooks": { "preToolUse": [ { "command": "./validate-shell.sh", "matcher": "Shell" } ], "subagentStart": [ { "command": "./validate-explore.sh", "matcher": "explore|shell" } ], "beforeShellExecution": [ { "command": "./approve-network.sh", "matcher": "curl|wget|nc " } ] }}- subagentStart: Matcher diterapkan pada jenis subagent (misalnya
explore,shell,generalPurpose). Gunakan untuk menjalankan hook hanya saat subagent jenis tertentu dimulai. Contoh di atas menjalankanvalidate-explore.shhanya untuk subagent explore atau shell. - beforeShellExecution: Matcher diterapkan pada string perintah shell. Gunakan untuk menjalankan hook hanya saat perintah cocok dengan pola tertentu (misalnya panggilan jaringan atau penghapusan file). Contoh di atas menjalankan
approve-network.shhanya saat perintah berisicurl,wget, ataunc.
Matcher yang tersedia untuk setiap hook:
- preToolUse / postToolUse / postToolUseFailure: Filter berdasarkan jenis alat. Nilainya mencakup
Shell,Read,Write,Grep,Delete,Task, dan alat MCP dengan formatMCP:<tool_name>. - subagentStart / subagentStop: Filter berdasarkan jenis subagent (
generalPurpose,explore,shell, dll.). - beforeShellExecution / afterShellExecution: Filter berdasarkan teks perintah shell; matcher dibandingkan dengan seluruh string perintah.
- beforeReadFile: Filter berdasarkan jenis alat (
TabRead,Read, dll.). - afterFileEdit: Filter berdasarkan jenis alat (
TabWrite,Write, dll.). - beforeSubmitPrompt: Dicocokkan dengan nilai
UserPromptSubmit. - stop: Dicocokkan dengan nilai
Stop. - afterAgentResponse: Dicocokkan dengan nilai
AgentResponse. - afterAgentThought: Dicocokkan dengan nilai
AgentThought.
Distribusi Tim
Hook dapat dibagikan kepada anggota tim melalui hook proyek (menggunakan sistem kontrol versi), alat MDM, atau sistem distribusi cloud Cursor.
Hook Proyek (Sistem Kontrol Versi)
Hook proyek adalah cara paling sederhana untuk membagikan hook kepada tim Anda. Letakkan file hooks.json di <project-root>/.cursor/hooks.json, lalu commit file tersebut ke repositori Anda. Saat anggota tim membuka proyek di workspace tepercaya, Cursor akan otomatis memuat dan menjalankan hook proyek.
Agen cloud juga memuat hook proyek ini saat mengerjakan repositori Anda di cloud.
Hook proyek:
- Disimpan dalam sistem kontrol versi bersama kode Anda
- Otomatis dimuat untuk semua anggota tim di workspace tepercaya
- Dapat bersifat khusus untuk proyek tertentu (misalnya, menerapkan standar pemformatan untuk codebase tertentu)
- Memerlukan workspace tepercaya agar dapat dijalankan (demi keamanan)
Distribusi MDM
Distribusikan hook di seluruh organisasi Anda menggunakan alat Mobile Device Management (MDM). Tempatkan file hooks.json dan skrip hook di direktori target pada setiap mesin.
Direktori home pengguna (distribusi per pengguna):
~/.cursor/hooks.json~/.cursor/hooks/(untuk skrip hook)
Direktori global (distribusi seluruh sistem):
- macOS:
/Library/Application Support/Cursor/hooks.json - Linux/WSL:
/etc/cursor/hooks.json - Windows:
C:\\ProgramData\\Cursor\\hooks.json
Catatan: Distribusi berbasis MDM sepenuhnya dikelola oleh organisasi Anda. Cursor tidak men-deploy atau mengelola file melalui solusi MDM Anda. Pastikan tim TI atau keamanan internal Anda menangani konfigurasi, deployment, dan pembaruan sesuai dengan kebijakan organisasi Anda.
Distribusi Cloud (Hanya Enterprise)
Tim Enterprise dapat menggunakan distribusi cloud bawaan Cursor untuk menyinkronkan hook secara otomatis ke semua anggota tim. Atur hook di dashboard web. Cursor secara otomatis mengirimkan hook yang telah dikonfigurasi ke semua mesin klien saat anggota tim masuk.
Distribusi cloud menyediakan:
- Sinkronisasi otomatis ke semua anggota tim (setiap tiga puluh menit)
- Penargetan sistem operasi untuk hook khusus platform
- Manajemen terpusat melalui dashboard
Administrator Enterprise dapat membuat, mengedit, dan mengelola team hooks dari dashboard tanpa memerlukan akses ke mesin masing-masing.
Hubungi sales untuk mendapatkan distribusi hook cloud Enterprise.
Referensi
Skema umum
Input (semua hook)
Semua hook menerima serangkaian field dasar, selain field khusus masing-masing hook:
{ "conversation_id": "string", "generation_id": "string", "model": "string", "model_id": "string", "model_params": [{ "id": "string", "value": "string" }], "hook_event_name": "string", "cursor_version": "string", "workspace_roots": ["<path>"], "user_email": "string | null", "transcript_path": "string | null"}| Field | Jenis | Deskripsi | |
|---|---|---|---|
conversation_id | string | ID percakapan yang tetap sama di banyak giliran | |
generation_id | string | Generasi saat ini yang berubah setiap kali ada pesan pengguna | |
model | string | Slug model lama yang dikonfigurasi untuk composer yang memicu hook | |
model_id | string (opsional) | ID terstruktur untuk model yang dipilih, jika tersedia | |
model_params | array (opsional) | Parameter model yang dipilih, seperti thinking, konteks, atau effort. Setiap item memiliki id dan value. | |
hook_event_name | string | Hook yang sedang dijalankan | |
cursor_version | string | Versi aplikasi Cursor (misalnya "1.7.2") | |
workspace_roots | string[] | Daftar folder root di workspace (biasanya hanya satu, tetapi workspace multi-root dapat memiliki beberapa) | |
user_email | string | null | Alamat email pengguna yang telah diautentikasi, jika tersedia |
transcript_path | string | null | Path ke file transkrip percakapan utama (null jika transkrip dinonaktifkan) |
Hook siklus hidup aplikasi (workspaceOpen) dipicu di luar sesi agent mana pun, sehingga permintaan tidak menyertakan conversation_id, generation_id, model, session_id, dan transcript_path. Hook ini tetap menerima hook_event_name, cursor_version, workspace_roots, dan user_email.
Peristiwa hook
preToolUse
Dipanggil sebelum eksekusi tool apa pun. Hook generik ini berjalan untuk semua jenis tool (Shell, Read, Write, MCP, Task, dll.). Gunakan matcher untuk memfilter tool tertentu.
// Input{ "tool_name": "Shell", "tool_input": { "command": "npm install", "working_directory": "/project" }, "tool_use_id": "abc123", "cwd": "/project", "model": "claude-opus-4-7-thinking-max", "model_id": "claude-opus-4-7", "model_params": [ { "id": "thinking", "value": "true" }, { "id": "context", "value": "1m" }, { "id": "effort", "value": "max" } ], "agent_message": "Installing dependencies..."}// Output{ "permission": "allow" | "deny", "user_message": "<message shown in client when denied>", "agent_message": "<message sent to agent when denied>", "updated_input": { "command": "npm ci" }}| Field Output | Jenis | Deskripsi |
|---|---|---|
permission | string | "allow" untuk melanjutkan, "deny" untuk memblokir. "ask" diterima oleh skema, tetapi saat ini tidak enforced untuk preToolUse. |
user_message | string (opsional) | Pesan yang ditampilkan kepada pengguna saat action ditolak |
agent_message | string (opsional) | Pesan yang dikirim kembali ke agent saat action ditolak |
updated_input | object (opsional) | Input tool yang telah dimodifikasi untuk digunakan sebagai gantinya |
postToolUse
Dipanggil setelah tool berhasil dijalankan. Berguna untuk audit, analitik, dan menyisipkan konteks.
// input{ "tool_name": "Shell", "tool_input": { "command": "npm test" }, "tool_output": "{\"exitCode\":0,\"stdout\":\"All tests passed\"}", "tool_use_id": "abc123", "cwd": "/project", "duration": 5432, "model": "claude-opus-4-7-thinking-max", "model_id": "claude-opus-4-7", "model_params": [ { "id": "thinking", "value": "true" }, { "id": "context", "value": "1m" }, { "id": "effort", "value": "max" } ]}// Output{ "updated_mcp_tool_output": { "modified": "output" }, "additional_context": "Test coverage report attached."}| Field input | Jenis | Deskripsi |
|---|---|---|
duration | number | Waktu eksekusi dalam milidetik |
tool_output | string | Payload hasil dari tool yang diserialisasi sebagai string JSON (bukan teks terminal mentah) |
| Field Output | Jenis | Deskripsi |
|---|---|---|
updated_mcp_tool_output | object (optional) | Khusus untuk alat MCP: menggantikan output tool yang dilihat model |
additional_context | string (optional) | Konteks tambahan yang disisipkan ke dalam percakapan setelah hasil tool |
postToolUseFailure
Dipanggil saat tool gagal, mengalami timeout, atau ditolak. Berguna untuk pelacakan error dan logika pemulihan.
// Input{ "tool_name": "Shell", "tool_input": { "command": "npm test" }, "tool_use_id": "abc123", "cwd": "/project", "error_message": "Command timed out after 30s", "failure_type": "timeout" | "error" | "permission_denied", "duration": 5000, "is_interrupt": false}// Output{ // Tidak ada kolom output yang didukung saat ini}| Field input | Jenis | Deskripsi |
|---|---|---|
error_message | string | Deskripsi kegagalan |
failure_type | string | Jenis kegagalan: "error", "timeout", atau "permission_denied" |
duration | number | Waktu dalam milidetik hingga kegagalan terjadi |
is_interrupt | boolean | Apakah kegagalan ini disebabkan oleh interupsi atau pembatalan oleh pengguna |
subagentStart
Dipanggil sebelum subagent dibuat (tool Task). Dapat mengizinkan atau melarang pembuatan subagent.
// Input{ "subagent_id": "abc-123", "subagent_type": "generalPurpose", "task": "Explore the authentication flow", "parent_conversation_id": "conv-456", "tool_call_id": "tc-789", "subagent_model": "claude-sonnet-4-20250514", "is_parallel_worker": false, "git_branch": "feature/auth"}// Output{ "permission": "allow" | "deny", "user_message": "<message shown when denied>"}| Field input | Jenis | Deskripsi |
|---|---|---|
subagent_id | string | Pengidentifikasi unik untuk instance subagent ini |
subagent_type | string | Jenis subagent: generalPurpose, explore, shell, dll. |
task | string | Deskripsi tugas yang diberikan kepada subagent |
parent_conversation_id | string | ID percakapan sesi agent induk |
tool_call_id | string | ID pemanggilan tool yang memicu subagent |
subagent_model | string | Model yang akan digunakan oleh subagent |
is_parallel_worker | boolean | Apakah subagent ini berjalan sebagai worker paralel |
git_branch | string (opsional) | Branch Git yang akan digunakan subagent, jika relevan |
| Field output | Jenis | Deskripsi |
|---|---|---|
permission | string | "allow" untuk melanjutkan, "deny" untuk memblokir. "ask" tidak didukung untuk subagentStart dan diperlakukan sebagai "deny". |
user_message | string (opsional) | Pesan yang ditampilkan kepada pengguna ketika subagent dilarang |
subagentStop
Dipanggil saat subagent selesai, mengalami error, atau dibatalkan. Dapat memicu tindakan tindak lanjut.
// input{ "subagent_type": "generalPurpose", "status": "completed" | "error" | "aborted", "task": "Explore the authentication flow", "description": "Exploring auth flow", "summary": "<subagent output summary>", "duration_ms": 45000, "message_count": 12, "tool_call_count": 8, "loop_count": 0, "modified_files": ["src/auth.ts"], "agent_transcript_path": "/path/to/subagent/transcript.txt"}// Output{ "followup_message": "<auto-continue with this message>"}| Field input | Jenis | Deskripsi | |
|---|---|---|---|
subagent_type | string | Jenis subagent: generalPurpose, explore, shell, dll. | |
status | string | "completed", "error", atau "aborted" | |
task | string | Deskripsi tugas yang diberikan kepada subagent | |
description | string | Deskripsi singkat tujuan subagent | |
summary | string | Ringkasan output subagent | |
duration_ms | number | Waktu eksekusi dalam milidetik | |
message_count | number | Jumlah pesan yang dipertukarkan selama sesi subagent | |
tool_call_count | number | Jumlah pemanggilan tool yang dilakukan subagent | |
loop_count | number | Jumlah tindak lanjut subagentStop yang telah dipicu untuk subagent ini (dimulai dari 0) | |
modified_files | string[] | File yang dimodifikasi subagent | |
agent_transcript_path | string | null | Path ke file transkrip subagent sendiri (terpisah dari percakapan induk) |
| Field output | Jenis | Deskripsi |
|---|---|---|
followup_message | string (opsional) | Lanjutkan otomatis dengan pesan ini. Hanya digunakan jika status adalah "completed". |
Field followup_message memungkinkan alur berbasis loop, dengan penyelesaian subagent memicu iterasi berikutnya. Tindak lanjut tunduk pada batas loop yang dapat dikonfigurasi, sama seperti hook stop (default 5, dapat dikonfigurasi melalui loop_limit).
beforeShellExecution / beforeMCPExecution
Dipanggil sebelum shell command atau tool MCP dijalankan. Kembalikan keputusan permission.
Secara default, kegagalan hook (crash, batas waktu, JSON tidak valid) tetap mengizinkan action dijalankan (fail-open). Atur failClosed: true pada definisi hook untuk memblokir action jika terjadi kegagalan. Ini disarankan untuk hook beforeMCPExecution yang sangat penting bagi security.
// Input beforeShellExecution{ "command": "<full terminal command>", "cwd": "<current working directory>", "sandbox": false}// Input beforeMCPExecution{ "tool_name": "<tool name>", "tool_input": "<json params>"}// Tambahkan salah satu:{ "url": "<server url>" }// Atau:{ "command": "<command string>" }// Output{ "permission": "allow" | "deny" | "ask", "user_message": "<message shown in client>", "agent_message": "<message sent to agent>"}afterShellExecution
Dipicu setelah perintah shell dieksekusi; berguna untuk audit atau mengumpulkan metrik dari output perintah.
// input{ "command": "<full terminal command>", "output": "<full terminal output>", "duration": 1234, "sandbox": false}| Field | Jenis | Deskripsi |
|---|---|---|
command | string | Perintah terminal lengkap yang dijalankan |
output | string | Seluruh output yang ditangkap dari terminal |
duration | number | Durasi dalam milidetik untuk menjalankan perintah shell (tidak termasuk waktu tunggu persetujuan) |
sandbox | boolean | Apakah perintah dijalankan di lingkungan tersandbox |
afterMCPExecution
Dipicu setelah tool MCP dieksekusi; mencakup parameter input tool dan hasil JSON lengkap.
// input{ "tool_name": "<nama alat>", "tool_input": "<parameter json>", "result_json": "<hasil json alat>", "duration": 1234}| Field | Jenis | Deskripsi |
|---|---|---|
tool_name | string | Nama tool MCP yang dijalankan |
tool_input | string | String parameter JSON yang diteruskan ke tool |
result_json | string | String JSON dari respons tool |
duration | number | Durasi dalam milidetik untuk menjalankan tool MCP (tidak termasuk waktu tunggu persetujuan) |
afterFileEdit
Dipicu setelah Agent mengedit file; berguna untuk pemformatan atau pencatatan kode yang ditulis agent.
// input{ "file_path": "<absolute path>", "edits": [{ "old_string": "<search>", "new_string": "<replace>" }]}beforeReadFile
Dipanggil sebelum Agent membaca file. Gunakan untuk kontrol akses guna mencegah file sensitif dikirim ke model.
Secara default, kegagalan hook beforeReadFile (crash, batas waktu, JSON tidak valid) dicatat dalam log dan pembacaan tetap diizinkan. Atur failClosed: true pada definisi hook agar pembacaan diblokir jika terjadi kegagalan.
// input{ "file_path": "<absolute path>", "content": "<file contents>", "attachments": [ { "type": "file" | "rule", "file_path": "<absolute path>" } ]}// Output{ "permission": "allow" | "deny", "user_message": "<message shown when denied>"}| Field input | Jenis | Deskripsi |
|---|---|---|
file_path | string | Path absolut file yang dibaca |
content | string | Seluruh isi file |
attachments | array | Lampiran konteks yang terkait dengan prompt. Setiap entri memiliki type ("file" atau "rule") dan file_path. |
| Field Output | Jenis | Deskripsi |
|---|---|---|
permission | string | "allow" untuk melanjutkan, "deny" untuk memblokir |
user_message | string (opsional) | Pesan yang ditampilkan kepada pengguna saat ditolak |
beforeTabFileRead
Dipanggil sebelum Tab (inline completions) membaca file. Aktifkan penyamaran data atau kontrol akses sebelum Tab mengakses isi file.
Perbedaan utama dengan beforeReadFile:
- Hanya dipicu oleh Tab, bukan Agent
- Tidak mencakup field
attachments(Tab tidak menggunakan lampiran prompt) - Berguna untuk menerapkan kebijakan yang berbeda pada operasi Tab otonom
// input{ "file_path": "<absolute path>", "content": "<file contents>"}// Output{ "permission": "allow" | "deny"}afterTabFileEdit
Dipanggil setelah Tab (inline completion) mengedit file. Berguna untuk pemformat atau mengaudit kode yang ditulis oleh Tab.
Perbedaan utama dengan afterFileEdit:
- Hanya dipicu oleh Tab, bukan Agent
- Mencakup informasi edit terperinci:
range,old_line, dannew_lineuntuk melacak edit secara akurat - Berguna untuk pemformatan atau analisis edit Tab secara terperinci
// input{ "file_path": "<absolute path>", "edits": [ { "old_string": "<search>", "new_string": "<replace>", "range": { "start_line_number": 10, "start_column": 5, "end_line_number": 10, "end_column": 20 }, "old_line": "<line before edit>", "new_line": "<line after edit>" } ]}// Output{ // Tidak ada kolom output yang didukung saat ini}beforeSubmitPrompt
Dipanggil tepat setelah pengguna menekan Kirim, tetapi sebelum permintaan dikirim ke backend. Dapat mencegah pengiriman.
// Input{ "prompt": "<user prompt text>", "attachments": [ { "type": "file" | "rule", "file_path": "<absolute path>" } ]}// Output{ "continue": true | false, "user_message": "<message shown to user when blocked>"}| Field Output | Jenis | Deskripsi |
|---|---|---|
continue | boolean | Menentukan apakah pengiriman prompt dapat dilanjutkan |
user_message | string (optional) | Pesan yang ditampilkan kepada pengguna saat prompt diblokir |
afterAgentResponse
Dipanggil setelah agent selesai membuat pesan asisten.
// input{ "text": "<assistant final text>"}afterAgentThought
Dipanggil setelah agent menyelesaikan blok pemikiran. Berguna untuk mengamati proses penalaran agent.
// Input{ "text": "<fully aggregated thinking text>", "duration_ms": 5000}// Output{ // Tidak ada kolom output yang didukung saat ini}| Field | Type | Deskripsi |
|---|---|---|
text | string | Teks thinking gabungan lengkap untuk blok yang telah selesai |
duration_ms | number (opsional) | Durasi blok thinking dalam milidetik |
stop
Dipanggil saat Agent Loop berakhir. Secara opsional, dapat otomatis mengirim pesan tindak lanjut pengguna untuk melanjutkan iterasi.
// input{ "status": "completed" | "aborted" | "error", "loop_count": 0}// Output{ "followup_message": "<message text>"}followup_messageopsional berupa string. Jika diberikan dan tidak kosong, Cursor akan otomatis mengirimkannya sebagai pesan pengguna berikutnya. Ini memungkinkan alur berbasis loop (misalnya, mengulang hingga tujuan tercapai).- Field
loop_countmenunjukkan berapa kali hook stop telah memicu tindak lanjut otomatis untuk percakapan ini (mulai dari 0). Batas defaultnya adalah 5 tindak lanjut otomatis per skrip dan dapat dikonfigurasi melalui opsiloop_limit. Aturloop_limitkenulluntuk menghapus batas tersebut. Batas yang sama berlaku untuk tindak lanjutsubagentStop.
sessionStart
Dipanggil saat percakapan composer baru dibuat. Hook ini berjalan secara fire-and-forget; Agent Loop tidak menunggu atau mewajibkan respons yang memblokir. Gunakan untuk menyiapkan variabel lingkungan khusus sesi atau menyuntikkan konteks tambahan.
// input{ "session_id": "<unique session identifier>", "is_background_agent": true | false, "composer_mode": "agent" | "ask" | "edit"}// Output{ "env": { "<key>": "<value>" }, "additional_context": "<context to add to conversation>"}| Field input | Jenis | Deskripsi |
|---|---|---|
session_id | string | Pengidentifikasi unik untuk sesi ini (sama dengan conversation_id) |
is_background_agent | boolean | Menunjukkan apakah ini sesi agen latar belakang atau sesi interaktif |
composer_mode | string (opsional) | Mode saat composer dimulai (misalnya, "agent", "ask", "edit") |
| Field Output | Jenis | Deskripsi |
|---|---|---|
env | object (opsional) | Variabel lingkungan yang diatur untuk sesi ini. Tersedia untuk semua eksekusi hook berikutnya |
additional_context | string (opsional) | Konteks tambahan yang ditambahkan ke konteks sistem awal percakapan |
Skema juga menerima field continue dan user_message, tetapi pemanggil saat ini tidak mewajibkannya. Pembuatan sesi tidak diblokir meskipun continue bernilai false.
sessionEnd
Dipanggil saat percakapan composer berakhir. Hook fire-and-forget ini berguna untuk tugas logging, analytics, atau cleanup. Respons dicatat, tetapi tidak digunakan.
// Input{ "session_id": "<pengidentifikasi sesi unik>", "reason": "completed" | "aborted" | "error" | "window_close" | "user_close", "duration_ms": 45000, "is_background_agent": true | false, "final_status": "<string status>", "error_message": "<detail kesalahan jika reason adalah 'error'>"}// Output{ // Tidak ada field output — jalankan tanpa menunggu hasil}| Field input | Jenis | Deskripsi |
|---|---|---|
session_id | string | Pengidentifikasi unik untuk sesi yang berakhir |
reason | string | Alasan sesi berakhir: "completed", "aborted", "error", "window_close", atau "user_close" |
duration_ms | number | Total durasi sesi dalam milidetik |
is_background_agent | boolean | Apakah ini adalah sesi agen latar belakang |
final_status | string | Status akhir sesi |
error_message | string (optional) | Pesan kesalahan jika reason adalah "error" |
preCompact
Dipanggil sebelum pemadatan/peringkasan jendela konteks dilakukan. Hook observasional ini tidak dapat memblokir atau mengubah perilaku pemadatan. Berguna untuk mencatat kapan pemadatan dilakukan atau memberi tahu pengguna.
// input{ "trigger": "auto" | "manual", "context_usage_percent": 85, "context_tokens": 120000, "context_window_size": 128000, "message_count": 45, "messages_to_compact": 30, "is_first_compaction": true | false}// Output{ "user_message": "<message to show when compaction occurs>"}| Field input | Jenis | Deskripsi |
|---|---|---|
trigger | string | Pemicu compaction: "auto" atau "manual" |
context_usage_percent | number | Penggunaan jendela konteks saat ini dalam persentase (0-100) |
context_tokens | number | Jumlah token saat ini dalam jendela konteks |
context_window_size | number | Ukuran maksimum jendela konteks dalam token |
message_count | number | Jumlah pesan dalam percakapan |
messages_to_compact | number | Jumlah pesan yang akan diringkas |
is_first_compaction | boolean | Apakah ini compaction pertama dalam percakapan ini |
| Field output | Jenis | Deskripsi |
|---|---|---|
user_message | string (optional) | Pesan yang ditampilkan kepada pengguna saat compaction terjadi |
workspaceOpen
Dipicu satu kali saat Cursor membuka workspace, lalu kembali dipicu setiap kali folder workspace berubah. Tidak dipicu jika jendela tidak memiliki folder workspace. Berjalan di aplikasi desktop Cursor dan CLI.
// Input{ "hook_event_name": "workspaceOpen", "cursor_version": "string", "workspace_roots": ["<absolute path>"], "user_email": "string | null"}// Output{ "pluginPaths": ["<absolute path>", "..."]}| Field Output | Jenis | Deskripsi |
|---|---|---|
pluginPaths | string[] (opsional) | Path absolut ke direktori plugin yang dimuat untuk workspace saat ini. |
Variabel Lingkungan
Skrip hook menerima variabel lingkungan saat dijalankan:
| Variabel | Deskripsi | Selalu Tersedia |
|---|---|---|
CURSOR_PROJECT_DIR | Direktori root workspace | Ya |
CURSOR_VERSION | String versi Cursor | Ya |
CURSOR_USER_EMAIL | Email pengguna yang diautentikasi | Jika sudah login |
CURSOR_TRANSCRIPT_PATH | Path ke file transkrip percakapan | Jika transkrip diaktifkan |
CURSOR_CODE_REMOTE | Diatur ke string "true" saat berjalan di workspace remote | Untuk workspace remote |
CLAUDE_PROJECT_DIR | Alias untuk direktori proyek (kompatibilitas Claude) | Ya |
Variabel lingkungan cakupan sesi dari hook sessionStart diteruskan ke semua eksekusi hook berikutnya dalam sesi tersebut.
Pemecahan masalah
Cara memastikan hook aktif
Terdapat tab Hooks di Customize dan channel output Hooks untuk men-debug hook yang telah diatur dan dijalankan, serta melihat error.
Jika hook tidak berfungsi
- Cursor memantau file
hooks.jsondan memuat ulang saat disimpan. Jika hook tetap tidak dimuat, mulai ulang Cursor. - Pastikan path relatif sudah benar untuk sumber hook Anda:
- Untuk hook proyek, path relatif terhadap root proyek (misalnya,
.cursor/hooks/script.sh) - Untuk hook pengguna, path relatif terhadap
~/.cursor/(misalnya,./hooks/script.shatauhooks/script.sh)
- Untuk hook proyek, path relatif terhadap root proyek (misalnya,
Pemblokiran kode keluar
Kode keluar 2 dari hook perintah memblokir tindakan (setara dengan mengembalikan permission: "deny"). Ini sesuai dengan perilaku Claude Code untuk compatibility.
Hook Enterprise dan distribusi
Distribusi Cloud dan manajemen hook di seluruh tim tersedia di Enterprise.