> ## Documentation Index
> Fetch the complete documentation index at: https://code.claude.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Bereaksi terhadap peristiwa dengan mod

> Tangani peristiwa Claude Code dari mod: amati, tulis ulang, atau jawab panggilan alat, prompt, dan giliran, saring peristiwa mana yang ditangani hook, dan rencanakan untuk mod lain.

Hook adalah penanganan peristiwa: fungsi yang dijalankan Claude Code ketika peristiwa bernama terjadi. Claude Code mengeluarkan peristiwa di setiap titik di mana ia akan bertindak, seperti ketika menjalankan alat, mengirimkan prompt, mengirim permintaan ke model, atau memulai atau mengakhiri sesi. Hook Anda berjalan sebelum Claude Code bertindak, sehingga dapat mengamati peristiwa, menulis ulangnya, atau menjawabnya sebagai pengganti Claude Code. Anda mendaftarkan hook dengan [`on(eventName, handler)`](/docs/id/plugins/mods/reference#the-hook-function).

Bangun [mod pertama Anda](/docs/id/plugins/mods/create) sebelum Anda mulai di sini. Untuk setiap peristiwa dan bidangnya yang tepat, lihat [referensi](/docs/id/plugins/mods/reference#events) atau baca [tipe untuk build Anda](/docs/id/plugins/mods/create#get-the-types-for-your-build).

<h2 id="how-a-hook-handles-an-event">
  Bagaimana hook menangani peristiwa
</h2>

Hook duduk di antara peristiwa dan apa yang akan dilakukan Claude Code tentangnya, sehingga dapat mengamati peristiwa, menulis ulangnya, atau menjawabnya sendiri. Hook menerima tiga argumen: [mods API](/docs/id/plugins/mods/api) sebagai `$`, peristiwa sebagai `e`, dan penanganan berikutnya sebagai `next`. Penanganan untuk peristiwa membentuk rantai middleware. `next(e)` memanggil penanganan berikutnya, yang merupakan hook mod lain atau, di akhir rantai, perilaku Claude Code sendiri, dan diselesaikan dengan hasilnya. Apa yang dilakukan hook Anda dengan `next` menentukan mana dari ketiga hal itu yang dilakukannya.

<h3 id="observe-an-event">
  Amati peristiwa
</h3>

Untuk mengamati peristiwa tanpa mengubahnya, lakukan pekerjaan Anda dan kembalikan `next(e)`. Hook ini mencatat setiap alat yang akan digunakan Claude:

```javascript theme={null}
on('tool.call', async ($, e, next) => {
  // Berjalan sebelum alat dijalankan
  $.ui.log('Claude is about to use ' + e.tool)
  // Teruskan peristiwa tanpa perubahan
  return next(e)
})
```

Sebelum setiap alat dijalankan, baris redup seperti `● my-mod: Claude is about to use Bash` muncul dalam transkrip, di mana `my-mod` adalah nama plugin Anda. Alat berjalan seperti yang akan terjadi tanpa mod.

Untuk bertindak setelah peristiwa, `await next(e)`, lakukan pekerjaan Anda, dan kembalikan hasilnya. Hook ini mencatat setiap alat setelah dijalankan:

```javascript theme={null}
on('tool.call', async ($, e, next) => {
  // Biarkan alat berjalan, dan tunggu hasilnya
  const result = await next(e)
  // Berjalan setelah alat selesai
  $.ui.log(e.tool + ' finished')
  // Berikan hasil kembali tanpa perubahan
  return result
})
```

Baris sekarang muncul setelah setiap alat selesai. Claude membaca hasil yang sama dengan cara apa pun, karena hook mengembalikan apa yang diselesaikan `next(e)`.

<h3 id="rewrite-an-event">
  Tulis ulang peristiwa
</h3>

Untuk mengubah apa yang Claude Code bertindak, seperti teks prompt, panggil `next` dengan salinan peristiwa yang dimodifikasi. Peristiwa itu sendiri tidak dapat diubah: peristiwa itu dibekukan di setiap kedalaman, dan penugasan ke bidang melempar. Hook ini memangkas setiap prompt sebelum dikirim:

```javascript theme={null}
on('prompt.submit', async ($, e, next) => {
  // Teruskan salinan peristiwa dengan teksnya diubah
  return next({ ...e, text: e.text.trim() })
})
```

Penanganan berikutnya dan Claude Code menerima prompt yang dipangkas dan tidak pernah melihat yang asli. Anda juga dapat mengubah hasilnya: `await next(e)`, kemudian kembalikan salinan hasil dengan bidang yang diganti.

<h3 id="answer-an-event">
  Jawab peristiwa
</h3>

Untuk menangani peristiwa sendiri, kembalikan hasil tanpa memanggil `next`. Itu memotong rantai, sehingga mod berikutnya dan perilaku Claude Code sendiri tidak berjalan. Hook ini menolak setiap perintah Bash:

```javascript theme={null}
on('tool.call', { tool: 'Bash' }, async () => {
  // Tidak ada panggilan ke next, jadi perintah tidak pernah dijalankan
  return { deny: 'Bash is turned off in this project. Use the file tools.' }
})
```

Ketika Claude mencoba perintah Bash, perintah tidak berjalan, dan Claude membaca teks `deny` sebagai hasil alat. Setiap peristiwa memiliki bentuk hasil sendiri, yang [referensi peristiwa](/docs/id/plugins/mods/reference#events) daftarkan.

<h3 id="filter-which-events-a-hook-handles">
  Saring peristiwa mana yang ditangani hook
</h3>

Untuk menjalankan hook hanya untuk beberapa peristiwa, teruskan filter sebagai argumen kedua ke `on`. Claude Code memanggil filter sebagai matcher. Ini adalah objek yang bidangnya dibandingkan dengan peristiwa, dan hook hanya berjalan ketika setiap bidang cocok. Bidang dapat berupa nilai, array nilai yang diizinkan, atau ekspresi reguler.

Setiap baris dalam contoh ini mendaftarkan fungsi yang sama, `hook`, untuk set panggilan alat yang lebih sempit:

```javascript theme={null}
// String cocok dengan satu nilai: hanya panggilan Bash
on('tool.call', { tool: 'Bash' }, hook)
// Array cocok dengan nilai apa pun di dalamnya: panggilan Edit dan Write
on('tool.call', { tool: ['Edit', 'Write'] }, hook)
// Ekspresi reguler cocok dengan pola: setiap alat dari satu server MCP
on('tool.call', { tool: /^mcp__github__/ }, hook)
```

`hook` berjalan sekali untuk panggilan Bash, Edit, atau Write, dan sekali untuk panggilan ke alat yang namanya dimulai dengan `mcp__github__`. Panggilan ke alat lain apa pun, seperti Read, tidak cocok dengan ketiga hal itu, jadi `hook` tidak berjalan untuk itu.

Nama peristiwa dapat berupa wildcard. `'classic.*'` cocok dengan setiap [peristiwa hook pengaturan](#hook-the-settings-hook-events). `'*'` cocok dengan setiap peristiwa kecuali [peristiwa telemetri](/docs/id/plugins/mods/reference#telemetry), yang Anda hook berdasarkan nama atau sebagai `'telemetry.*'`.

Daftarkan setiap peristiwa sekali per matcher. Jika Anda memanggil `on` dua kali untuk `session.start` tanpa matcher, modul gagal dimuat dengan `on("session.start") is registered twice without a matcher`. Masukkan semua yang dilakukan mod Anda saat memulai sesi dalam satu hook.

<h2 id="hook-what-claude-is-doing">
  Hook apa yang dilakukan Claude
</h2>

Hook peristiwa ini untuk melihat atau mengubah panggilan alat, prompt, atau giliran saat terjadi. Untuk setiap peristiwa dan apa yang dapat dikembalikan hook, lihat [referensi peristiwa](/docs/id/plugins/mods/reference#events).

<h3 id="guard-or-change-a-tool-call">
  Lindungi atau ubah panggilan alat
</h3>

Hook `tool.call` melihat setiap alat yang akan digunakan Claude, sehingga dapat menolak panggilan, mengubah argumennya, atau membiarkannya. `tool.call` diaktifkan ketika Claude Code akan menjalankan alat, termasuk panggilan yang dibuat subagen dan panggilan ke alat MCP. `e.tool` adalah nama alat dan argumen alat adalah bidang `e`, seperti `e.command` untuk Bash. Ketika Anda memanggil `next(e)`, Claude Code menjalankan pemeriksaan izin dan kemudian alat.

Hook ini menolak perintah Bash yang force-push, dan memberi tahu Claude mengapa:

```javascript theme={null}
// Matcher membatasi hook ke panggilan Bash, jadi e.command adalah perintah shell
on('tool.call', { tool: 'Bash' }, async ($, e, next) => {
  if (/git push .*--force/.test(e.command)) {
    // Mengembalikan tanpa memanggil next menjawab peristiwa, jadi perintah tidak pernah dijalankan
    return { deny: 'Force pushes are not allowed in this repository. Push to a new branch instead.' }
  }
  // Setiap perintah lain melanjutkan ke pemeriksaan izin dan kemudian ke Bash
  return next(e)
})
```

Ketika Claude mencoba `git push --force`, perintah tidak berjalan dan tidak ada prompt izin muncul, karena hook tidak pernah memanggil `next`. Claude membaca teks `deny` sebagai hasil alat, jadi tulislah sebagai instruksi yang dapat ditindaklanjuti Claude. Setiap perintah Bash lain berjalan seperti yang akan terjadi tanpa mod.

Untuk bertindak setelah alat telah berjalan, `await next(e)`, lakukan pekerjaan Anda, dan kembalikan apa yang diberikan `next`. Hook ini mencatat setiap file `.mdx` yang diubah Claude, dengan [`$.ui.log`](/docs/id/plugins/mods/api#show-something-without-starting-a-turn), yang menambahkan baris redup ke transkrip yang tidak dibaca Claude:

```javascript theme={null}
on('tool.call', { tool: ['Edit', 'Write'] }, async ($, e, next) => {
  // Tunggu pemeriksaan izin dan alat, dan simpan apa yang mereka hasilkan
  const result = await next(e)
  // Panggilan yang ditolak kembali sebagai { deny }, dan yang gagal memiliki isError yang ditetapkan
  const changed = !result.deny && !result.isError
  if (changed && e.file_path.endsWith('.mdx')) $.ui.log('Claude changed ' + e.file_path)
  // Kembalikan hasil seperti yang datang, sehingga Claude membaca apa yang dikembalikan alat
  return result
})
```

Setelah Claude mengedit atau menulis file `.mdx`, baris redup dalam transkrip menamai file. Tidak ada yang dicatat untuk jenis file lain, atau untuk panggilan yang ditolak atau gagal. Pandangan Claude tentang panggilan tidak berubah, karena hook mengembalikan hasil yang diterima.

Untuk mengubah panggilan, teruskan argumen yang diubah ke `next`. Untuk mencoba ulang panggilan, panggil `next(e)` lagi: hook yang melihat `isError` pada hasil pertama dapat menjalankan alat kedua kali dan mengembalikan hasil itu. Untuk menjawab panggilan sendiri, kembalikan objek dengan bidang `result`, seperti `{ result: 'Skipped by my-mod' }`, tanpa memanggil `next`. Ketika Anda melakukan itu, tidak ada prompt izin yang muncul dan alat tidak berjalan, jadi hasil yang Anda kembalikan adalah semua yang dipelajari Claude tentang apa yang terjadi.

Hook dalam [pengaturan terkelola](/docs/id/server-managed-settings) organisasi Anda berjalan sebelum hook `tool.call` mod apa pun, dan blok dari salah satu dari mereka adalah final.

<h4 id="hold-a-tool-call-until-the-user-decides">
  Tahan panggilan alat sampai pengguna memutuskan
</h4>

Hook dapat menjeda panggilan alat dan menanyakan kepada pengguna apa yang harus dilakukan sebelum melanjutkan. Hook `tool.call` dapat `await` sebelum memanggil `next` atau mengembalikan, dan panggilan alat tetap tertunda sampai saat itu. Untuk mengajukan pertanyaan kepada pengguna, panggil `$.ui.ask`. Ini menampilkan pertanyaan Anda di atas daftar bernomor opsi Anda, dalam dialog yang digunakan Claude untuk menanyakan sesuatu kepada Anda, dan diselesaikan dengan label yang dipilih pengguna. Setelah opsi Anda, dialog menambahkan baris untuk mengetik jawaban berbeda dan baris **Chat about this**.

Pola `RISKY` dalam contoh ini cocok dengan `rm -r`, `rm -rf`, `git reset --hard`, dan `git push` dengan `--force`, dan melewatkan ejaan lain seperti `git push -f`. Modul ini menanyakan sebelum menjalankan perintah Bash yang cocok dengan pola:

```javascript theme={null}
const RISKY = /\brm\s+-rf?\b|\bgit\s+reset\s+--hard\b|\bgit\s+push\b.*--force/

export function register(on) {
  on('tool.call', { tool: 'Bash' }, async ($, e, next) => {
    // Biarkan setiap perintah lain melalui tanpa pertanyaan
    if (!RISKY.test(e.command)) return next(e)
    // Mulai dari jawaban yang aman, sehingga pertanyaan yang tidak dijawab siapa pun menolak perintah
    let answer = 'Refuse'
    try {
      // Panggilan alat menunggu di sini sampai pengguna memilih salah satu dari dua label
      answer = await $.ui.ask('Run this command? ' + e.command, ['Run it', 'Refuse'])
    } catch {
      // Pengguna membatalkan pertanyaan, atau ini adalah jalankan claude -p tanpa siapa pun untuk ditanyai
    }
    if (answer !== 'Run it') {
      // Jawab tanpa memanggil next, jadi perintah tidak berjalan
      return { deny: 'The user declined this command. Ask before trying a different approach.' }
    }
    return next(e)
  })
}
```

Ketika Claude mencoba perintah seperti `rm -rf build`, pertanyaan muncul dengan perintah di dalamnya, dan perintah menunggu jawaban:

* **Pengguna memilih Run it**: hook memanggil `next(e)`, dan pemeriksaan izin biasa masih berjalan setelahnya
* **Pengguna memilih Refuse**: perintah tidak berjalan, dan Claude membaca teks `deny`
* **Pengguna mengetik jawaban**: `$.ui.ask` diselesaikan dengan teks yang diketik. Hook membandingkannya dengan `Run it`, jadi teks lain apa pun menolak perintah.
* **Tidak ada yang menjawab**: `$.ui.ask` menolak ketika pengguna membatalkan pertanyaan atau memilih **Chat about this**, dan dalam jalankan `claude -p`, jadi blok `catch` membiarkan jawaban di `Refuse`

Simpan tunggu di dalam panggilan mods API seperti `$.ui.ask`, karena waktu itu tidak dihitung terhadap [batas waktu 10 detik](/docs/id/plugins/mods/reference#limits) hook. Waktu yang dihabiskan menunggu janji Anda sendiri dihitung. Claude Code melewati hook yang habis waktu, jadi perintah yang ditahan akan berjalan.

<h3 id="rewrite-or-add-to-a-prompt">
  Tulis ulang atau tambahkan ke prompt
</h3>

Hook `prompt.submit` melihat setiap prompt sebelum giliran dimulai, sehingga dapat menulis ulang teks atau menambahnya. `e.text` adalah apa yang diketik.

| Untuk melakukan ini | Kembalikan ini |
| :- | :- |
| Tulis ulang prompt. Pesan dalam transkrip menampilkan teks baru. | `next({ ...e, text: newText })` |
| Tambahkan teks hanya Claude baca, setelah prompt | `next({ ...e, context: [...(e.context ?? []), extraText] })` |
| Hentikan prompt dari pengiriman | `{ drop: 'the reason' }` |

Hook ini menambahkan nama cabang saat ini untuk Claude setiap kali prompt menyebutkan permintaan tarik:

```javascript theme={null}
on('prompt.submit', async ($, e, next) => {
  // Teruskan prompt yang tidak menyebutkan permintaan tarik seperti apa adanya
  if (!/\bPR\b|pull request/i.test(e.text)) return next(e)
  const git = await $.process.run(['git', 'branch', '--show-current'])
  // Di luar repositori git perintah gagal, jadi tidak ada cabang untuk ditambahkan
  if (git.exitCode !== 0) return next(e)
  // Simpan konteks apa pun yang ditambahkan hook sebelumnya, dan tambahkan satu baris lagi untuk Claude
  return next({ ...e, context: [...(e.context ?? []), 'Current branch: ' + git.stdout.trim()] })
})
```

Ketika Anda mengirim prompt seperti `open a PR for this change`, pesan Anda terlihat sama dalam transkrip, dan Claude juga membaca baris seperti `Current branch: feature/auth` setelahnya. Prompt yang tidak menyebutkan permintaan tarik melewati tanpa perubahan, dan `git` tidak berjalan.

[Peristiwa lain](/docs/id/plugins/mods/reference#prompts-and-what-claude-reads) mencakup sisa apa yang dibaca Claude: `prompt.section` untuk setiap bagian prompt sistem, `prompt.context` untuk konteks yang dikirim dengan pesan pertama, dan `skill.prompt` untuk teks skill. Teks dari hook ini yang berubah antara permintaan [membatalkan cache prompt](/docs/id/prompt-caching).

<h3 id="follow-a-turn">
  Ikuti giliran
</h3>

Giliran adalah semua yang dilakukan Claude sebagai jawaban atas satu prompt. Hook `turn.start`, `turn.step`, dan `turn.complete` untuk mengikuti satu:

| Peristiwa | Kapan diaktifkan | Apa yang dapat dilakukan hook |
| :- | :- | :- |
| `turn.start` | Giliran dimulai | Amati. `e.turnId` mengidentifikasi giliran dalam dua peristiwa lainnya. |
| `turn.step` | Claude Code akan mengirim satu permintaan ke model. Giliran dengan panggilan alat memiliki beberapa. `e.agentId` ditetapkan untuk permintaan subagen. | Baca penggunaan token setiap permintaan, kirimkan ke model berbeda dengan `next({ ...e, model })`, atau jawab tanpa memanggil model |
| `turn.complete` | Giliran berakhir, termasuk giliran yang diinterupsi pengguna, di mana `e.isAborted` adalah `true`. `e.answer` adalah teks final Claude, `e.durationMs` berapa lama waktu yang dibutuhkan, dan `e.usage` total token giliran. Giliran subagen mengeluarkannya dengan `e.agentId` ditetapkan. | Amati, atau kembalikan objek dengan bidang `text`, seperti `{ text: 'Done in 12 seconds' }`, untuk menampilkan baris di bawah jawaban |

Tulis hook `turn.step` sebagai generator asinkron, karena peristiwa mengalir. `yield* next(e)` meneruskan respons saat mengalir dan mengevaluasi hasil yang selesai. Hook ini mencatat berapa banyak dari setiap permintaan yang dilayani Claude API dari [cache prompt](/docs/id/prompt-caching):

```javascript theme={null}
// function* membuat hook menjadi generator, yang dapat meneruskan respons sepotong demi sepotong
on('turn.step', async function* ($, e, next) {
  // Kirim permintaan, teruskan setiap bagian saat tiba, dan simpan hasil yang selesai
  const result = yield* next(e)
  // Lewati hasil yang tidak melaporkan hitungan token
  if (result.usage) {
    $.ui.log('cache read ' + result.usage.cache_read_input_tokens + ' · wrote ' + result.usage.cache_creation_input_tokens)
  }
  // Kembalikan hasil tanpa perubahan, sehingga giliran berlanjut seperti biasa
  return result
})
```

Respons Claude mengalir ke layar seperti yang terjadi tanpa mod. Setelah setiap permintaan selesai, baris redup dalam transkrip memberikan jumlah token yang dibaca dari cache dan jumlah yang ditulis ke dalamnya. Giliran dengan panggilan alat memiliki beberapa permintaan, jadi menambahkan beberapa baris.

`result.usage` menyimpan empat hitungan token yang dilaporkan Claude API untuk permintaan, ditambah `model` yang menjawab: `input_tokens`, `output_tokens`, `cache_read_input_tokens`, dan `cache_creation_input_tokens`. Hook berjalan untuk permintaan subagen juga, jadi periksa `e.agentId` ketika Anda hanya menginginkan percakapan utama.

<h3 id="hook-the-settings-hook-events">
  Hook peristiwa hook pengaturan
</h3>

Hook pengaturan adalah hook perintah, HTTP, prompt, dan agen yang Anda konfigurasi dalam file pengaturan. Setiap [peristiwa hook pengaturan](/docs/id/hooks#hook-events), seperti `Stop`, `SessionEnd`, atau `PostToolUse`, juga merupakan peristiwa bernama `classic.` diikuti dengan nama peristiwa hook pengaturan, seperti `classic.Stop`. `e` adalah JSON yang diterima hook pengaturan di stdin, termasuk `transcript_path`.

Hook ini menggunakan `Stop`, yang diaktifkan ketika Claude selesai merespons, untuk mencatat di mana transkrip sesi disimpan:

```javascript theme={null}
on('classic.Stop', async ($, e, next) => {
  // e memiliki bidang yang sama yang dibaca hook Stop dalam file pengaturan dari stdin
  $.ui.log('Transcript saved at ' + e.transcript_path)
  // Teruskan peristiwa, sehingga hook Stop dalam file pengaturan Anda masih berjalan
  return next(e)
})
```

Setiap kali Claude selesai merespons, baris redup dalam transkrip memberikan jalur file transkrip. Hook mengembalikan `next(e)`, sehingga mengamati peristiwa dan tidak mengubah apa pun tentang cara giliran berakhir.

<h2 id="run-alongside-other-mods">
  Jalankan bersama mod lain
</h2>

Beberapa mod dapat hook peristiwa yang sama, dan salah satu dari mereka dapat gagal. Jika mod Anda memblokir panggilan alat, periksa posisinya dalam rantai dan apa yang terjadi ketika hooknya gagal.

<h3 id="the-order-mods-run-in">
  Urutan mod berjalan
</h3>

Hook pada peristiwa yang sama membentuk satu rantai middleware. Setiap `next` mod memanggil hook mod berikutnya, dan `next` terakhir mencapai perilaku Claude Code sendiri. Mod pertama adalah terluar: melihat peristiwa sebelum yang lain dan hasil setelah mereka, dan menentukan apakah yang lain berjalan sama sekali. Mod yang lebih baru tidak dapat menghentikan yang lebih awal dari melihat peristiwa.

Claude Code mengurutkan rantai berdasarkan tempat asal setiap mod:

1. Guard bawaan `sec-default@builtin`, mod yang dibangun ke dalam Claude Code yang `/plugin` daftarkan sebagai `cc-plugin-sec-default`, di mana [dimuat](/docs/id/plugins/mods/admin#know-what-happens-by-default), mod yang organisasi Anda daftarkan dalam [`prependPlugins`](/docs/id/plugins/mods/admin#install-your-organizations-mods), dan kemudian mod lain apa pun yang dihitung sebagai organisasi Anda dan tidak dalam `appendPlugins`
2. Mod yang Anda instal
3. Mod yang organisasi Anda daftarkan dalam `appendPlugins`
4. Mod bawaan lain yang dibangun ke dalam Claude Code

Di antara mod yang Anda instal, mod berjalan sebelum mod yang didaftarkan di bawah `dependencies` dalam manifestnya. Dalam satu modul, hook berjalan dalam urutan `register` yang disebut `on`.

<h4 id="where-settings-hooks-run-in-the-order">
  Di mana hook pengaturan berjalan dalam urutan
</h4>

Hook `PreToolUse` yang dikonfigurasi dalam file pengaturan juga berjalan selama panggilan alat, pada titik tetap dalam rantai mod:

* **Hook `PreToolUse` dari pengaturan terkelola**: berjalan sebelum hook `tool.call` mod pertama, dan blok dari salah satu dari mereka adalah final, jadi tidak ada mod yang melihat panggilan.
* **Hook `PreToolUse` dari setiap file pengaturan lain dan dari `hooks/hooks.json` plugin**: berjalan setelah mod terakhir memanggil `next`, sebagai bagian dari perilaku Claude Code sendiri. Mod yang menjawab `tool.call` tanpa memanggil `next` mencegah mereka berjalan, dan mod yang memanggil `next` melihat keputusan mereka dalam hasil yang dikembalikan.

[`tool.check`](/docs/id/plugins/mods/reference#tools) adalah peristiwa di mana Claude Code memutuskan apakah panggilan alat dapat berjalan. Peristiwa ini diaktifkan setelah hook tersebut dan aturan izin telah memutuskan, dan `next(e)` diselesaikan dengan keputusan mereka. Hook pada `tool.check` dapat mengembalikan keputusan berbeda, seperti `{ decision: 'allow' }`, sehingga dapat menyetujui panggilan yang diblokir hook di grup kedua. [Perluas izin dengan hook](/docs/id/permissions#extend-permissions-with-hooks) mencantumkan keputusan mana yang berlaku atas mod.

<h3 id="handle-a-hook-that-fails">
  Tangani hook yang gagal
</h3>

Hook yang gagal tidak merusak sesi, dan Anda dapat memutuskan apa yang terjadi sebagai gantinya. Ketika hook tanpa penanganan `.catch` melempar, habis waktu, atau mengembalikan hasil bentuk yang salah, apa yang terjadi selanjutnya tergantung pada apakah telah memanggil `next`:

* **Gagal sebelum memanggil `next`**: Claude Code melewatinya, dan penanganan berikutnya berjalan sebagai gantinya
* **Gagal setelah `next` diselesaikan**: hasil itu berdiri, dan tidak ada yang berjalan kedua kalinya

Satu baris menamai mod, peristiwa, dan alasan, seperti `my-mod: tool.call hook skipped: threw Error: boom`. Tempat Anda membacanya tergantung pada sesi, seperti [Cari tahu mengapa mod tidak melakukan apa pun](/docs/id/plugins/mods/troubleshoot#find-out-why-a-mod-does-nothing) daftarkan. Hook `ui.render` yang gambarnya tidak divalidasi dilaporkan berbeda, seperti [Bangun pohon dari elemen](/docs/id/plugins/mods/interface#build-a-tree-from-elements) menjelaskan.

Untuk membuat hook yang memblokir panggilan gagal tertutup, tambahkan penanganan kesalahan `.catch` yang menjawab sebagai gantinya. Di sini, `guard` adalah fungsi hook Anda:

```javascript theme={null}
// on mengembalikan pendaftaran, dan .catch melampirkan penanganan ke hook itu saja
on('tool.call', { tool: 'Bash' }, guard).catch(async ($, e, next) => {
  // next.error.kind adalah 'throw' atau 'timeout', yang mengatakan bagaimana guard gagal
  return { deny: 'The command guard failed, so this command was not run: ' + next.error.kind }
})
```

Sementara `guard` bekerja, penanganan tidak pernah berjalan. Ketika `guard` melempar atau habis waktu pada panggilan Bash, Claude Code memanggil penanganan dengan peristiwa yang sama. Penanganan mengembalikan `{ deny }`, jadi perintah tidak berjalan, dan Claude membaca teks dengan `throw` atau `timeout` di akhir. Tanpa penanganan, Claude Code akan melewati `guard` dan menjalankan perintah. Penanganan memiliki [satu detik](/docs/id/plugins/mods/reference#limits) untuk menjawab.

<h2 id="next-steps">
  Langkah berikutnya
</h2>

* [Gunakan mods API](/docs/id/plugins/mods/api): tambahkan perintah dan alat, panggil model, dan jalankan pekerjaan pada timer
* [Gambar di antarmuka](/docs/id/plugins/mods/interface): tampilkan apa yang dikumpulkan hook Anda dalam panel atau di atas prompt
* [Uji mod](/docs/id/plugins/mods/test): naikkan salah satu peristiwa ini dari tes
* [Referensi mods](/docs/id/plugins/mods/reference): setiap peristiwa, setiap metode mods API, dan batasnya
