4 4
5# Reaccionar a eventos con un mod5# Reaccionar a eventos con un mod
6 6
7> Maneja eventos de Claude Code desde un mod: observa, reescribe o responde llamadas de herramientas, indicaciones y turnos, filtra qué eventos maneja un hook y planifica para otros mods.7> Maneja eventos de Claude Code desde un mod: observa, reescribe o responde llamadas a herramientas, prompts y turnos, filtra qué eventos maneja un hook y planifica para otros mods.
8 8
9Un hook es un manejador de eventos: una función que Claude Code ejecuta cuando ocurre un evento nombrado. Claude Code dispara un evento en cada punto donde está a punto de actuar, como cuando ejecuta una herramienta, envía una indicación, envía una solicitud al modelo, o inicia o termina una sesión. Tu hook se ejecuta antes de que Claude Code actúe, por lo que puede observar el evento, reescribirlo o responderlo en lugar de Claude Code. Registras un hook con [`on(eventName, handler)`](/docs/es/plugins/mods/reference#the-hook-function).9Un hook es un manejador de eventos: una función que Claude Code ejecuta cuando ocurre un evento con nombre. Claude Code dispara un evento en cada punto en el que está a punto de actuar, por ejemplo, cuando ejecuta una herramienta, envía un prompt, envía una solicitud al modelo, o inicia o finaliza una sesión. Tu hook se ejecuta antes de que Claude Code actúe, por lo que puede observar el evento, reescribirlo o responderlo en lugar de Claude Code. Registras un hook con [`on(eventName, handler)`](/docs/es/plugins/mods/reference#the-hook-function).
10 10
11Construye tu [primer mod](/docs/es/plugins/mods/create) antes de empezar aquí. Para cada evento y sus campos exactos, consulta la [referencia](/docs/es/plugins/mods/reference#events) o lee [los tipos para tu compilación](/docs/es/plugins/mods/create#get-the-types-for-your-build).11Crea tu [primer mod](/docs/es/plugins/mods/create) antes de empezar aquí. Para ver cada evento y sus campos exactos, consulta la [referencia](/docs/es/plugins/mods/reference#events) o lee [los tipos para tu compilación](/docs/es/plugins/mods/create#get-the-types-for-your-build).
12 12
13<h2 id="how-a-hook-handles-an-event">13<h2 id="how-a-hook-handles-an-event">
14 Cómo un hook maneja un evento14 Cómo un hook gestiona un evento
15</h2>15</h2>
16 16
17Un hook se sitúa entre un evento y lo que Claude Code haría al respecto, por lo que puede observar el evento, reescribirlo o responderlo él mismo. Recibe tres argumentos: la [API de mods](/docs/es/plugins/mods/api) como `$`, el evento como `e`, y el siguiente manejador como `next`. Los manejadores de un evento forman una cadena de middleware. `next(e)` llama al siguiente manejador, que es el hook de otro mod o, al final de la cadena, el comportamiento propio de Claude Code, y se resuelve al resultado. Lo que tu hook hace con `next` decide cuál de los tres hace.17Un hook se sitúa entre un evento y lo que Claude Code haría al respecto, por lo que puede observar el evento, reescribirlo o responderlo por sí mismo. Recibe tres argumentos: la [API de mods](/docs/es/plugins/mods/api) como `$`, el evento como `e` y el siguiente manejador como `next`. Los manejadores de un evento forman una cadena de middleware. `next(e)` llama al siguiente manejador, que es el hook de otro mod o, al final de la cadena, el comportamiento propio de Claude Code, y se resuelve con el resultado. Lo que tu hook haga con `next` decide cuál de las tres cosas hace.
18 18
19<h3 id="observe-an-event">19<h3 id="observe-an-event">
20 Observar un evento20 Observar un evento
24 24
25```javascript theme={null}25```javascript theme={null}
26on('tool.call', async ($, e, next) => {26on('tool.call', async ($, e, next) => {
27 // Se ejecuta antes de que la herramienta se ejecute27 // Runs before the tool does
28 $.ui.log('Claude is about to use ' + e.tool)28 $.ui.log('Claude is about to use ' + e.tool)
29 // Pasa el evento sin cambios29 // Pass the event on unchanged
30 return next(e)30 return next(e)
31})31})
32```32```
33 33
34Antes de que cada herramienta se ejecute, aparece una línea atenuada como `● my-mod: Claude is about to use Bash` en la transcripción, donde `my-mod` es el nombre de tu plugin. La herramienta se ejecuta como lo haría sin el mod.34Antes de que se ejecute cada herramienta, aparece en la transcripción una línea atenuada como `● my-mod: Claude is about to use Bash`, donde `my-mod` es el nombre de tu plugin. La herramienta se ejecuta como lo haría sin el mod.
35 35
36Para actuar después del evento, `await next(e)`, haz tu trabajo y devuelve el resultado. Este hook registra cada herramienta después de que se ha ejecutado:36Para actuar después del evento, usa `await next(e)`, haz tu trabajo y devuelve el resultado. Este hook registra cada herramienta después de que se ha ejecutado:
37 37
38```javascript theme={null}38```javascript theme={null}
39on('tool.call', async ($, e, next) => {39on('tool.call', async ($, e, next) => {
40 // Deja que la herramienta se ejecute y espera su resultado40 // Let the tool run, and wait for its result
41 const result = await next(e)41 const result = await next(e)
42 // Se ejecuta después de que la herramienta se ejecuta42 // Runs after the tool does
43 $.ui.log(e.tool + ' finished')43 $.ui.log(e.tool + ' finished')
44 // Devuelve el resultado sin cambios44 // Give the result back unchanged
45 return result45 return result
46})46})
47```47```
48 48
49La línea ahora aparece después de que cada herramienta termina. Claude lee el mismo resultado de cualquier manera, porque el hook devuelve lo que `next(e)` se resolvió.49Ahora la línea aparece después de que termina cada herramienta. Claude lee el mismo resultado en ambos casos, porque el hook devuelve aquello con lo que se resolvió `next(e)`.
50 50
51<h3 id="rewrite-an-event">51<h3 id="rewrite-an-event">
52 Reescribir un evento52 Reescribir un evento
53</h3>53</h3>
54 54
55Para cambiar lo que Claude Code actúa, como el texto de una indicación, llama a `next` con una copia modificada del evento. El evento en sí es inmutable: está congelado en cada profundidad, y asignar a un campo lanza una excepción. Este hook recorta cada indicación antes de que se envíe:55Para cambiar aquello sobre lo que actúa Claude Code, como el texto de un prompt, llama a `next` con una copia modificada del evento. El evento en sí es inmutable: está congelado en profundidad, y asignar un valor a un campo lanza una excepción. Este hook recorta cada prompt antes de enviarlo:
56 56
57```javascript theme={null}57```javascript theme={null}
58on('prompt.submit', async ($, e, next) => {58on('prompt.submit', async ($, e, next) => {
59 // Pasa una copia del evento con su texto cambiado59 // Pass on a copy of the event with its text changed
60 return next({ ...e, text: e.text.trim() })60 return next({ ...e, text: e.text.trim() })
61})61})
62```62```
63 63
64Los manejadores posteriores y Claude Code reciben la indicación recortada y nunca ven la original. También puedes cambiar el resultado: `await next(e)`, luego devuelve una copia del resultado con un campo reemplazado.64Los manejadores posteriores y Claude Code reciben el prompt recortado y nunca ven el original. También puedes cambiar el resultado: usa `await next(e)` y luego devuelve una copia del resultado con un campo reemplazado.
65 65
66<h3 id="answer-an-event">66<h3 id="answer-an-event">
67 Responder un evento67 Responder un evento
68</h3>68</h3>
69 69
70Para manejar un evento tú mismo, devuelve un resultado sin llamar a `next`. Eso cortocircuita la cadena, por lo que los mods posteriores y el comportamiento propio de Claude Code no se ejecutan. Este hook rechaza cada comando Bash:70Para gestionar un evento tú mismo, devuelve un resultado sin llamar a `next`. Eso interrumpe la cadena, por lo que los mods posteriores y el comportamiento propio de Claude Code no se ejecutan. Este hook rechaza todos los comandos de Bash:
71 71
72```javascript theme={null}72```javascript theme={null}
73on('tool.call', { tool: 'Bash' }, async () => {73on('tool.call', { tool: 'Bash' }, async () => {
74 // Sin llamada a next, por lo que el comando nunca se ejecuta74 // No call to next, so the command never runs
75 return { deny: 'Bash is turned off in this project. Use the file tools.' }75 return { deny: 'Bash is turned off in this project. Use the file tools.' }
76})76})
77```77```
78 78
79Cuando Claude intenta un comando Bash, el comando no se ejecuta y Claude lee el texto `deny` como el resultado de la herramienta. Cada evento tiene su propia forma de resultado, que la [referencia de eventos](/docs/es/plugins/mods/reference#events) enumera.79Cuando Claude intenta un comando de Bash, el comando no se ejecuta, y Claude lee el texto de `deny` como el resultado de la herramienta. Cada evento tiene su propia forma de resultado, que se indica en la [referencia de eventos](/docs/es/plugins/mods/reference#events).
80 80
81<h3 id="filter-which-events-a-hook-handles">81<h3 id="filter-which-events-a-hook-handles">
82 Filtrar qué eventos maneja un hook82 Filtrar qué eventos gestiona un hook
83</h3>83</h3>
84 84
85Para ejecutar un hook solo para algunos eventos, pasa un filtro como segundo argumento a `on`. Claude Code llama al filtro un matcher. Es un objeto cuyos campos se comparan con los del evento, y el hook se ejecuta solo cuando cada campo coincide. Un campo puede ser un valor, una matriz de valores permitidos o una expresión regular.85Para ejecutar un hook solo para algunos eventos, pasa un filtro como segundo argumento de `on`. Claude Code llama al filtro un matcher. Es un objeto cuyos campos se comparan con los del evento, y el hook se ejecuta solo cuando todos los campos coinciden. Un campo puede ser un valor, un array de valores permitidos o una expresión regular.
86 86
87Cada línea en este ejemplo registra la misma función, `hook`, para un conjunto más estrecho de llamadas de herramientas:87Cada línea de este ejemplo registra la misma función, `hook`, para un conjunto más reducido de llamadas a herramientas:
88 88
89```javascript theme={null}89```javascript theme={null}
90// Una cadena coincide con un valor: solo llamadas Bash90// A string matches one value: Bash calls only
91on('tool.call', { tool: 'Bash' }, hook)91on('tool.call', { tool: 'Bash' }, hook)
92// Una matriz coincide con cualquier valor en ella: llamadas Edit y Write92// An array matches any value in it: Edit calls and Write calls
93on('tool.call', { tool: ['Edit', 'Write'] }, hook)93on('tool.call', { tool: ['Edit', 'Write'] }, hook)
94// Una expresión regular coincide por patrón: cada herramienta de un servidor MCP94// A regular expression matches by pattern: every tool of one MCP server
95on('tool.call', { tool: /^mcp__github__/ }, hook)95on('tool.call', { tool: /^mcp__github__/ }, hook)
96```96```
97 97
98`hook` se ejecuta una vez para una llamada Bash, Edit o Write, y una vez para una llamada a una herramienta cuyo nombre comienza con `mcp__github__`. Una llamada a cualquier otra herramienta, como Read, no coincide con ninguna de las tres, por lo que `hook` no se ejecuta para ella.98`hook` se ejecuta una vez para una llamada a Bash, Edit o Write, y una vez para una llamada a una herramienta cuyo nombre empieza por `mcp__github__`. Una llamada a cualquier otra herramienta, como Read, no coincide con ninguna de las tres, por lo que `hook` no se ejecuta para ella.
99 99
100El nombre del evento puede ser un comodín. `'classic.*'` coincide con cada [evento de hook de configuración](#hook-the-settings-hook-events). `'*'` coincide con cada evento excepto los [eventos de telemetría](/docs/es/plugins/mods/reference#telemetry), que enganchas por nombre o como `'telemetry.*'`.100El nombre del evento puede ser un comodín. `'classic.*'` coincide con todos los [eventos de hooks de configuración](#hook-the-settings-hook-events). `'*'` coincide con todos los eventos excepto los [eventos de telemetría](/docs/es/plugins/mods/reference#telemetry), que requieren su propio nombre y un filtro `{ to: 'collector' }`.
101 101
102Registra cada evento una vez por matcher. Si llamas a `on` dos veces para `session.start` sin un matcher, el módulo falla al cargar con `on("session.start") is registered twice without a matcher`. Pon todo lo que tu mod hace al inicio de la sesión en un hook.102Registra cada evento una sola vez por matcher. Si llamas a `on` dos veces para `session.start` sin matcher, el módulo no se carga y muestra `on("session.start") is registered twice without a matcher`. Pon todo lo que tu mod hace al inicio de la sesión en un solo hook.
103 103
104<h2 id="hook-what-claude-is-doing">104<h2 id="hook-what-claude-is-doing">
105 Enganchar lo que Claude está haciendo105 Engancha lo que Claude está haciendo
106</h2>106</h2>
107 107
108Engancha estos eventos para ver o cambiar una llamada de herramienta, una indicación o un turno mientras sucede. Para cada evento y lo que un hook puede devolver, consulta la [referencia de eventos](/docs/es/plugins/mods/reference#events).108Maneja estos eventos para ver o cambiar una llamada a herramienta, un prompt o un turno mientras ocurre. Para ver cada evento y lo que un hook puede devolver, consulta la [referencia de eventos](/docs/es/plugins/mods/reference#events).
109 109
110<h3 id="guard-or-change-a-tool-call">110<h3 id="guard-or-change-a-tool-call">
111 Guardar o cambiar una llamada de herramienta111 Proteger o cambiar una llamada a herramienta
112</h3>112</h3>
113 113
114Un hook `tool.call` ve cada herramienta que Claude está a punto de usar, por lo que puede rechazar la llamada, cambiar sus argumentos o dejarla pasar. `tool.call` se dispara cuando Claude Code está a punto de ejecutar una herramienta, incluidas las llamadas que hacen los subagentes y las llamadas a herramientas MCP. `e.tool` es el nombre de la herramienta y los argumentos de la herramienta son campos de `e`, como `e.command` para Bash. Cuando llamas a `next(e)`, Claude Code ejecuta la verificación de permisos y luego la herramienta.114Un hook `tool.call` ve cada herramienta que Claude está a punto de usar, así que puede rechazar la llamada, cambiar sus argumentos o dejarla pasar. `tool.call` se dispara cuando Claude Code está a punto de ejecutar una herramienta, incluidas las llamadas que hace un subagente y las llamadas a herramientas MCP. `e.tool` es el nombre de la herramienta y los argumentos de la herramienta son campos de `e`, como `e.command` para Bash. Cuando llamas a `next(e)`, Claude Code ejecuta la verificación de permisos y luego la herramienta.
115 115
116Este hook rechaza un comando Bash que hace un push forzado y le dice a Claude por qué:116Este hook rechaza un comando de Bash que hace un force push y le dice a Claude por qué:
117 117
118```javascript theme={null}118```javascript theme={null}
119// El matcher limita el hook a llamadas Bash, por lo que e.command es el comando del shell119// The matcher limits the hook to Bash calls, so e.command is the shell command
120on('tool.call', { tool: 'Bash' }, async ($, e, next) => {120on('tool.call', { tool: 'Bash' }, async ($, e, next) => {
121 if (/git push .*--force/.test(e.command)) {121 if (/git push .*--force/.test(e.command)) {
122 // Devolver sin llamar a next responde el evento, por lo que el comando nunca se ejecuta122 // Returning without calling next answers the event, so the command never runs
123 return { deny: 'Force pushes are not allowed in this repository. Push to a new branch instead.' }123 return { deny: 'Force pushes are not allowed in this repository. Push to a new branch instead.' }
124 }124 }
125 // Cada otro comando va a la verificación de permisos y luego a Bash125 // Every other command goes on to the permission check and then to Bash
126 return next(e)126 return next(e)
127})127})
128```128```
129 129
130Cuando Claude intenta `git push --force`, el comando no se ejecuta y no aparece ningún aviso de permiso, porque el hook nunca llama a `next`. Claude lee el texto `deny` como el resultado de la herramienta, así que escríbelo como una instrucción en la que Claude pueda actuar. Cada otro comando Bash se ejecuta como lo haría sin el mod.130Cuando Claude intenta `git push --force`, el comando no se ejecuta y no aparece ninguna solicitud de permiso, porque el hook nunca llama a `next`. Claude lee el texto de `deny` como el resultado de la herramienta, así que escríbelo como una instrucción sobre la que Claude pueda actuar. Cualquier otro comando de Bash se ejecuta como lo haría sin el mod.
131 131
132Para actuar después de que una herramienta se ha ejecutado, `await next(e)`, haz tu trabajo y devuelve lo que `next` te dio. Este hook registra cada archivo `.mdx` que Claude cambia, con [`$.ui.log`](/docs/es/plugins/mods/api#show-something-without-starting-a-turn), que añade una línea atenuada a la transcripción que Claude no lee:132Para actuar después de que una herramienta se haya ejecutado, usa `await next(e)`, haz tu trabajo y devuelve lo que `next` te dio. Este hook registra cada archivo `.mdx` que Claude cambia, con [`$.ui.log`](/docs/es/plugins/mods/api#show-something-without-starting-a-turn), que agrega a la transcripción una línea atenuada que Claude no lee:
133 133
134```javascript theme={null}134```javascript theme={null}
135on('tool.call', { tool: ['Edit', 'Write'] }, async ($, e, next) => {135on('tool.call', { tool: ['Edit', 'Write'] }, async ($, e, next) => {
136 // Espera la verificación de permisos y la herramienta, y mantén lo que produjeron136 // Wait for the permission check and the tool, and keep what they produced
137 const result = await next(e)137 const result = await next(e)
138 // Una llamada rechazada vuelve como { deny }, y una fallida tiene isError establecido138 // A refused call comes back as { deny }, and a failed one has isError set
139 const changed = !result.deny && !result.isError139 const changed = !result.deny && !result.isError
140 if (changed && e.file_path.endsWith('.mdx')) $.ui.log('Claude changed ' + e.file_path)140 if (changed && e.file_path.endsWith('.mdx')) $.ui.log('Claude changed ' + e.file_path)
141 // Devuelve el resultado tal como vino, para que Claude lea lo que la herramienta devolvió141 // Return the result as it came, so Claude reads what the tool returned
142 return result142 return result
143})143})
144```144```
145 145
146Después de que Claude edita o escribe un archivo `.mdx`, una línea atenuada en la transcripción nombra el archivo. Nada se registra para otro tipo de archivo, o para una llamada que fue rechazada o falló. La vista de Claude de la llamada no cambia, porque el hook devuelve el resultado que recibió.146Después de que Claude edita o escribe un archivo `.mdx`, una línea atenuada en la transcripción nombra el archivo. No se registra nada para otro tipo de archivo, ni para una llamada que fue rechazada o falló. La vista que Claude tiene de la llamada no cambia, porque el hook devuelve el resultado que recibió.
147 147
148Para cambiar una llamada, pasa argumentos cambiados a `next`. Para reintentar una llamada, llama a `next(e)` de nuevo: un hook que ve `isError` en el primer resultado puede ejecutar la herramienta una segunda vez y devolver ese resultado. Para responder una llamada tú mismo, devuelve un objeto con un campo `result`, como `{ result: 'Skipped by my-mod' }`, sin llamar a `next`. Cuando haces eso, no aparece ningún aviso de permiso y la herramienta no se ejecuta, por lo que el resultado que devuelves es todo lo que Claude aprende sobre lo que sucedió.148Para cambiar una llamada, pasa argumentos modificados a `next`. Para reintentar una llamada, vuelve a llamar a `next(e)`: un hook que ve `isError` en el primer resultado puede ejecutar la herramienta una segunda vez y devolver ese resultado. Para responder tú mismo a una llamada, devuelve un objeto con un campo `result`, como `{ result: 'Skipped by my-mod' }`, sin llamar a `next`. Cuando haces eso, no aparece ninguna solicitud de permiso y la herramienta no se ejecuta, así que el resultado que devuelves es todo lo que Claude sabe sobre lo que pasó.
149 149
150Los hooks en la [configuración administrada](/docs/es/server-managed-settings) de tu organización se ejecutan antes que el hook `tool.call` de cualquier mod, y un bloqueo de uno de ellos es final.150Los hooks de la [configuración administrada](/docs/es/server-managed-settings) de tu organización se ejecutan antes que el hook `tool.call` de cualquier mod, y un bloqueo de uno de ellos es definitivo.
151 151
152<h4 id="hold-a-tool-call-until-the-user-decides">152<h4 id="hold-a-tool-call-until-the-user-decides">
153 Mantener una llamada de herramienta hasta que el usuario decida153 Retener una llamada a herramienta hasta que el usuario decida
154</h4>154</h4>
155 155
156Un hook puede pausar una llamada de herramienta y preguntarle al usuario qué hacer antes de que continúe. Un hook `tool.call` puede `await` antes de llamar a `next` o devolver, y la llamada de herramienta permanece pendiente hasta entonces. Para hacer la pregunta al usuario, llama a `$.ui.ask`. Muestra tu pregunta encima de una lista numerada de tus opciones, en el diálogo que Claude usa para preguntarte algo, y se resuelve a la etiqueta que el usuario elige. Después de tus opciones, el diálogo añade una fila para escribir una respuesta diferente y una fila **Chat about this**.156Un hook puede pausar una llamada a herramienta y preguntarle al usuario qué hacer antes de que continúe. Un hook `tool.call` puede usar `await` antes de llamar a `next` o de devolver un valor, y la llamada a herramienta queda pendiente hasta entonces. Para plantearle la pregunta al usuario, llama a `$.ui.ask`. Muestra tu pregunta sobre una lista numerada de tus opciones, en el diálogo que Claude usa para preguntarte algo, y se resuelve con la etiqueta que elige el usuario. Después de tus opciones, el diálogo agrega una fila para escribir una respuesta diferente y una fila **Chat about this**.
157 157
158El patrón `RISKY` en este ejemplo coincide con `rm -r`, `rm -rf`, `git reset --hard` y `git push` con `--force`, y se pierde otras ortografías como `git push -f`. Este módulo pregunta antes de ejecutar un comando Bash que coincida con el patrón:158El patrón `RISKY` de este ejemplo coincide con `rm -r`, `rm -rf`, `git reset --hard` y `git push` con `--force`, y no detecta otras formas de escribirlos, como `git push -f`. Este módulo pregunta antes de ejecutar un comando de Bash que coincide con el patrón:
159 159
160```javascript theme={null}160```javascript theme={null}
161const RISKY = /\brm\s+-rf?\b|\bgit\s+reset\s+--hard\b|\bgit\s+push\b.*--force/161const RISKY = /\brm\s+-rf?\b|\bgit\s+reset\s+--hard\b|\bgit\s+push\b.*--force/
162 162
163export function register(on) {163export function register(on) {
164 on('tool.call', { tool: 'Bash' }, async ($, e, next) => {164 on('tool.call', { tool: 'Bash' }, async ($, e, next) => {
165 // Deja pasar cada otro comando sin una pregunta165 // Let every other command through without a question
166 if (!RISKY.test(e.command)) return next(e)166 if (!RISKY.test(e.command)) return next(e)
167 // Comienza desde la respuesta segura, por lo que una pregunta que nadie responde rechaza el comando167 // Start from the safe answer, so a question nobody answers refuses the command
168 let answer = 'Refuse'168 let answer = 'Refuse'
169 try {169 try {
170 // La llamada de herramienta espera aquí hasta que el usuario elige una de las dos etiquetas170 // The tool call waits here until the user picks one of the two labels
171 answer = await $.ui.ask('Run this command? ' + e.command, ['Run it', 'Refuse'])171 answer = await $.ui.ask('Run this command? ' + e.command, ['Run it', 'Refuse'])
172 } catch {172 } catch {
173 // El usuario descartó la pregunta, o esto es una ejecución de claude -p sin nadie a quien preguntar173 // The user dismissed the question, or this is a claude -p run with nobody to ask
174 }174 }
175 if (answer !== 'Run it') {175 if (answer !== 'Run it') {
176 // Responde sin llamar a next, por lo que el comando no se ejecuta176 // Answer without calling next, so the command doesn't run
177 return { deny: 'The user declined this command. Ask before trying a different approach.' }177 return { deny: 'The user declined this command. Ask before trying a different approach.' }
178 }178 }
179 return next(e)179 return next(e)
181}181}
182```182```
183 183
184Cuando Claude intenta un comando como `rm -rf build`, la pregunta aparece con el comando en ella, y el comando espera la respuesta:184Cuando Claude intenta un comando como `rm -rf build`, aparece la pregunta con el comando incluido, y el comando espera la respuesta:
185 185
186* **El usuario elige Run it**: el hook llama a `next(e)`, y la verificación de permisos habitual aún se ejecuta después186* **El usuario elige Run it**: el hook llama a `next(e)`, y la verificación de permisos habitual se sigue ejecutando después
187* **El usuario elige Refuse**: el comando no se ejecuta y Claude lee el texto `deny`187* **El usuario elige Refuse**: el comando no se ejecuta, y Claude lee el texto de `deny`
188* **El usuario escribe una respuesta**: `$.ui.ask` se resuelve al texto escrito. El hook lo compara con `Run it`, por lo que cualquier otro texto rechaza el comando.188* **El usuario escribe una respuesta**: `$.ui.ask` se resuelve con el texto escrito. El hook lo compara con `Run it`, así que cualquier otro texto rechaza el comando.
189* **Nadie responde**: `$.ui.ask` rechaza cuando el usuario descarta la pregunta o elige **Chat about this**, y en una ejecución de `claude -p`, por lo que el bloque `catch` deja la respuesta en `Refuse`189* **Nadie responde**: `$.ui.ask` se rechaza cuando el usuario descarta la pregunta o elige **Chat about this**, y en una ejecución de `claude -p`, así que el bloque `catch` deja la respuesta en `Refuse`
190 190
191Mantén la espera dentro de una llamada de API de mods como `$.ui.ask`, porque ese tiempo no cuenta contra el [límite de tiempo de 10 segundos](/docs/es/plugins/mods/reference#limits) del hook. El tiempo dedicado a esperar una promesa propia sí cuenta. Claude Code omite un hook que agota el tiempo, por lo que el comando retenido se ejecutaría.191Mantén la espera dentro de una llamada a la API de mods como `$.ui.ask`, porque ese tiempo no cuenta para el [límite de tiempo](/docs/es/plugins/mods/reference#limits) del hook. El tiempo dedicado a esperar una promesa propia sí cuenta. Claude Code omite un hook que agota el tiempo, así que el comando retenido se ejecutaría.
192
193<h4 id="approve-or-refuse-a-tool-call-before-the-user-is-asked">
194 Aprobar o rechazar una llamada a herramienta antes de preguntarle al usuario
195</h4>
196
197Para decidir si una llamada a herramienta puede ejecutarse, maneja [`tool.check`](/docs/es/plugins/mods/reference#tools), el evento en el que Claude Code toma esa decisión. Se dispara después de que las reglas de permisos y los hooks de configuración han decidido, y `next(e)` se resuelve con su decisión: `allow`, `ask` o `deny`. Tu hook devuelve esa decisión u otra diferente. `e.input` contiene los argumentos de la herramienta, como `command` para Bash.
198
199Para un comando o una ruta fijos, usa una [regla de permisos](/docs/es/permissions#permission-rule-syntax) como `Bash(npm test)`, que no requiere código. Maneja `tool.check` cuando la decisión depende de lo que es cierto en ese momento, como la rama de Git actual o un valor que otro hook registró.
200
201Este hook rechaza `git push` mientras la rama actual sea `main`:
202
203```javascript theme={null}
204on('tool.check', { tool: 'Bash' }, async ($, e, next) => {
205 // What the permission rules and settings hooks decided: 'allow', 'ask', or 'deny'
206 const decided = await next(e)
207 if (!e.input.command.includes('git push')) return decided
208 const branch = await $.process.run(['git', 'branch', '--show-current'])
209 if (branch.stdout.trim() !== 'main') return decided
210 return { decision: 'deny', reason: 'Push from a branch other than main' }
211})
212```
213
214En `main`, el hook devuelve `deny`, incluso cuando una regla permite `git push`. En otra rama, y para otros comandos, la llamada obtiene la decisión que obtendría sin el mod.
215
216El hook compara el texto del comando, así que trátalo como un recordatorio para Claude. Para bloquear los pushes a `main` para todos, protege la rama en tu host de Git.
217
218Un hook puede devolver `allow`, `ask` o `deny`, así que también puede aprobar una llamada que bloqueó un hook `PreToolUse` fuera de la configuración administrada. [Extender permisos con hooks](/docs/es/permissions#extend-permissions-with-hooks) indica qué decisiones prevalecen sobre un mod.
192 219
193<h3 id="rewrite-or-add-to-a-prompt">220<h3 id="rewrite-or-add-to-a-prompt">
194 Reescribir o añadir a una indicación221 Reescribir o agregar contenido a un prompt
195</h3>222</h3>
196 223
197Un hook `prompt.submit` ve cada indicación antes de que comience el turno, por lo que puede reescribir el texto o añadirle. `e.text` es lo que se escribió.224Un hook `prompt.submit` ve cada prompt antes de que comience el turno, así que puede reescribir el texto o agregarle contenido. `e.text` es lo que se escribió.
198 225
199| Para hacer esto | Devuelve esto |226| Para hacer esto | Devuelve esto |
200| :- | :- |227| :- | :- |
201| Reescribe la indicación. El mensaje en la transcripción muestra el nuevo texto. | `next({ ...e, text: newText })` |228| Reescribir el prompt. El mensaje en la transcripción muestra el texto nuevo. | `next({ ...e, text: newText })` |
202| Añade texto que solo Claude lee, después de la indicación | `next({ ...e, context: [...(e.context ?? []), extraText] })` |229| Agregar texto que solo Claude lee, después del prompt | `next({ ...e, context: [...(e.context ?? []), extraText] })` |
203| Detén el envío de la indicación | `{ drop: 'the reason' }` |230| Impedir que se envíe el prompt | `{ drop: 'the reason' }` |
204 231
205Este hook añade el nombre de la rama actual para Claude siempre que una indicación menciona una solicitud de extracción:232Este hook agrega el nombre de la rama actual para Claude siempre que un prompt menciona un pull request:
206 233
207```javascript theme={null}234```javascript theme={null}
208on('prompt.submit', async ($, e, next) => {235on('prompt.submit', async ($, e, next) => {
209 // Pasa una indicación que no menciona una solicitud de extracción tal como está236 // Pass on a prompt that doesn't mention a pull request as it is
210 if (!/\bPR\b|pull request/i.test(e.text)) return next(e)237 if (!/\bPR\b|pull request/i.test(e.text)) return next(e)
211 const git = await $.process.run(['git', 'branch', '--show-current'])238 const git = await $.process.run(['git', 'branch', '--show-current'])
212 // Fuera de un repositorio git el comando falla, por lo que no hay rama para añadir239 // Outside a git repository the command fails, so there's no branch to add
213 if (git.exitCode !== 0) return next(e)240 if (git.exitCode !== 0) return next(e)
214 // Mantén cualquier contexto que un hook anterior añadió, y añade una línea más para Claude241 // Keep any context an earlier hook added, and add one more line for Claude
215 return next({ ...e, context: [...(e.context ?? []), 'Current branch: ' + git.stdout.trim()] })242 return next({ ...e, context: [...(e.context ?? []), 'Current branch: ' + git.stdout.trim()] })
216})243})
217```244```
218 245
219Cuando envías una indicación como `open a PR for this change`, tu mensaje se ve igual en la transcripción, y Claude también lee una línea como `Current branch: feature/auth` después de ella. Una indicación que no menciona una solicitud de extracción pasa sin cambios, y `git` no se ejecuta.246Cuando envías un prompt como `open a PR for this change`, tu mensaje se ve igual en la transcripción, y Claude también lee una línea como `Current branch: feature/auth` después de él. Un prompt que no menciona un pull request pasa sin cambios, y `git` no se ejecuta.
220 247
221[Otros eventos](/docs/es/plugins/mods/reference#prompts-and-what-claude-reads) cubren el resto de lo que Claude lee: `prompt.section` para cada sección de la indicación del sistema, `prompt.context` para el contexto enviado con el primer mensaje, y `skill.prompt` para el texto de una skill. El texto de estos hooks que cambia entre solicitudes [invalida el caché de indicaciones](/docs/es/prompt-caching).248[Otros eventos](/docs/es/plugins/mods/reference#prompts-and-what-claude-reads) cubren el resto de lo que Claude lee: `prompt.section` para cada sección del prompt del sistema, `prompt.context` para el contexto enviado con el primer mensaje y `skill.prompt` para el texto de un skill. El texto de estos hooks que cambia entre solicitudes [invalida la caché de prompts](/docs/es/prompt-caching).
222 249
223<h3 id="follow-a-turn">250<h3 id="follow-a-turn">
224 Seguir un turno251 Seguir un turno
225</h3>252</h3>
226 253
227Un turno es todo lo que Claude hace en respuesta a una indicación. Engancha `turn.start`, `turn.step` y `turn.complete` para seguir uno:254Un turno es todo lo que Claude hace en respuesta a un prompt. Maneja `turn.start`, `turn.step` y `turn.complete` para seguir uno:
228 255
229| Evento | Cuándo se dispara | Qué puede hacer un hook |256| Evento | Cuándo se dispara | Qué puede hacer un hook |
230| :- | :- | :- |257| :- | :- | :- |
231| `turn.start` | Comienza un turno | Observa. `e.turnId` identifica el turno en los otros dos eventos. |258| `turn.start` | Comienza un turno | Observar. `e.turnId` identifica el turno en los otros dos eventos. |
232| `turn.step` | Claude Code está a punto de enviar una solicitud al modelo. Un turno con llamadas de herramientas tiene varias. `e.agentId` se establece para la solicitud de un subagente. | Lee el uso de tokens de cada solicitud, envíalo a un modelo diferente con `next({ ...e, model })`, o responde sin llamar al modelo |259| `turn.step` | Claude Code está a punto de enviar una solicitud al modelo. Un turno con llamadas a herramientas tiene varias. `e.agentId` está definido para la solicitud de un subagente. | Leer el uso de tokens de cada solicitud, enviarla a un modelo diferente con `next({ ...e, model })` o responder sin llamar al modelo |
233| `turn.complete` | El turno terminó, incluido un turno que el usuario interrumpió, donde `e.isAborted` es `true`. `e.answer` es el texto final de Claude, `e.durationMs` cuánto tiempo tomó, y `e.usage` los totales de tokens del turno. Un turno de subagente lo dispara con `e.agentId` establecido. | Observa, o devuelve un objeto con un campo `text`, como `{ text: 'Done in 12 seconds' }`, para mostrar una línea bajo la respuesta |260| `turn.complete` | El turno terminó, incluido un turno que el usuario interrumpió, en cuyo caso `e.isAborted` es `true`. `e.answer` es el texto final de Claude, `e.durationMs` cuánto tardó y `e.usage` los totales de tokens del turno. El turno de un subagente lo dispara con `e.agentId` definido. | Observar, o devolver un objeto con un campo `text`, como `{ text: 'Done in 12 seconds' }`, para mostrar una línea debajo de la respuesta |
234 261
235Escribe un hook `turn.step` como un generador asincrónico, porque el evento transmite. `yield* next(e)` reenvía la respuesta mientras se transmite y se evalúa al resultado terminado. Este hook registra cuánto de cada solicitud sirvió la API de Claude desde el [caché de indicaciones](/docs/es/prompt-caching):262Escribe un hook `turn.step` como un generador asíncrono, porque el evento se transmite por streaming. `yield* next(e)` reenvía la respuesta a medida que se transmite y se evalúa como el resultado terminado. Este hook registra cuánto de cada solicitud sirvió la API de Claude desde la [caché de prompts](/docs/es/prompt-caching):
236 263
237```javascript theme={null}264```javascript theme={null}
238// function* hace que el hook sea un generador, que puede pasar la respuesta pieza por pieza265// function* makes the hook a generator, which can pass the response on piece by piece
239on('turn.step', async function* ($, e, next) {266on('turn.step', async function* ($, e, next) {
240 // Envía la solicitud, reenvía cada pieza mientras llega, y mantén el resultado terminado267 // Send the request, forward each piece as it arrives, and keep the finished result
241 const result = yield* next(e)268 const result = yield* next(e)
242 // Omite un resultado que no reporta conteos de tokens269 // Skip a result that reports no token counts
243 if (result.usage) {270 if (result.usage) {
244 $.ui.log('cache read ' + result.usage.cache_read_input_tokens + ' · wrote ' + result.usage.cache_creation_input_tokens)271 $.ui.log('cache read ' + result.usage.cache_read_input_tokens + ' · wrote ' + result.usage.cache_creation_input_tokens)
245 }272 }
246 // Devuelve el resultado sin cambios, para que el turno continúe como de costumbre273 // Return the result unchanged, so the turn continues as usual
247 return result274 return result
248})275})
249```276```
250 277
251La respuesta de Claude se transmite a la pantalla como lo haría sin el mod. Después de que cada solicitud termina, una línea atenuada en la transcripción da el número de tokens leídos del caché y el número escrito en él. Un turno con llamadas de herramientas tiene varias solicitudes, por lo que añade varias líneas.278La respuesta de Claude se transmite a la pantalla igual que sin el mod. Después de que termina cada solicitud, una línea atenuada en la transcripción indica el número de tokens leídos de la caché y el número escritos en ella. Un turno con llamadas a herramientas tiene varias solicitudes, así que agrega varias líneas.
252 279
253`result.usage` contiene los cuatro conteos de tokens que la API de Claude reporta para una solicitud, más el `model` que respondió: `input_tokens`, `output_tokens`, `cache_read_input_tokens` y `cache_creation_input_tokens`. El hook se ejecuta para las solicitudes de subagentes también, por lo que verifica `e.agentId` cuando quieres solo la conversación principal.280`result.usage` contiene los recuentos de tokens que la API de Claude informa para una solicitud, además del `model` que respondió: `input_tokens`, `output_tokens`, `cache_read_input_tokens` y `cache_creation_input_tokens`. El hook también se ejecuta para las solicitudes de los subagentes, así que comprueba `e.agentId` cuando solo quieras la conversación principal.
254 281
255<h3 id="hook-the-settings-hook-events">282<h3 id="hook-the-settings-hook-events">
256 Enganchar los eventos de hook de configuración283 Manejar los eventos de los hooks de configuración
257</h3>284</h3>
258 285
259Los hooks de configuración son los hooks de comando, HTTP, indicación y agente que configuras en archivos de configuración. Cada [evento de hook de configuración](/docs/es/hooks#hook-events), como `Stop`, `SessionEnd` o `PostToolUse`, es también un evento nombrado `classic.` seguido del nombre del evento de hook de configuración, como `classic.Stop`. `e` es el JSON que un hook de configuración recibe en stdin, incluido `transcript_path`.286Los hooks de configuración son los hooks de comando, HTTP, prompt y agente que configuras en los archivos de configuración. Cada [evento de hook de configuración](/docs/es/hooks#hook-events), como `Stop`, `SessionEnd` o `PostToolUse`, también es un evento llamado `classic.` seguido del nombre del evento del hook de configuración, como `classic.Stop`. `e` es el JSON que un hook de configuración recibe por stdin, incluido `transcript_path`.
260 287
261Este hook usa `Stop`, que se dispara cuando Claude termina de responder, para registrar dónde se guarda la transcripción de la sesión:288Este hook usa `Stop`, que se dispara cuando Claude termina de responder, para registrar dónde se guarda la transcripción de la sesión:
262 289
263```javascript theme={null}290```javascript theme={null}
264on('classic.Stop', async ($, e, next) => {291on('classic.Stop', async ($, e, next) => {
265 // e tiene los mismos campos que un hook Stop en un archivo de configuración lee de stdin292 // e has the same fields a Stop hook in a settings file reads from stdin
266 $.ui.log('Transcript saved at ' + e.transcript_path)293 $.ui.log('Transcript saved at ' + e.transcript_path)
267 // Pasa el evento, para que los hooks Stop en tus archivos de configuración aún se ejecuten294 // Pass the event on, so Stop hooks in your settings files still run
268 return next(e)295 return next(e)
269})296})
270```297```
271 298
272Cada vez que Claude termina de responder, una línea atenuada en la transcripción da la ruta del archivo de transcripción. El hook devuelve `next(e)`, por lo que observa el evento y no cambia nada sobre cómo termina el turno.299Cada vez que Claude termina de responder, una línea atenuada en la transcripción indica la ruta del archivo de transcripción. El hook devuelve `next(e)`, así que observa el evento y no cambia nada de cómo termina el turno.
273 300
274<h2 id="run-alongside-other-mods">301<h2 id="run-alongside-other-mods">
275 Ejecutar junto a otros mods302 Ejecutar junto con otros mods
276</h2>303</h2>
277 304
278Varios mods pueden enganchar el mismo evento, y cualquiera de ellos puede fallar. Si tu mod bloquea llamadas de herramientas, verifica su posición en la cadena y qué sucede cuando su hook falla.305Varios mods pueden manejar el mismo evento, y cualquiera de ellos puede fallar. Si tu mod bloquea llamadas a herramientas, revisa su posición en la cadena y qué sucede cuando su hook falla.
279 306
280<h3 id="the-order-mods-run-in">307<h3 id="the-order-mods-run-in">
281 El orden en que se ejecutan los mods308 El orden en que se ejecutan los mods
282</h3>309</h3>
283 310
284Los hooks en el mismo evento forman una cadena de middleware. Cada `next` de un mod llama al hook del siguiente mod, y el último `next` llega al comportamiento propio de Claude Code. El primer mod es el más externo: ve el evento antes que los otros y el resultado después de ellos, y decide si los otros se ejecutan en absoluto. Un mod posterior no puede detener a uno anterior de ver un evento.311Los hooks de un mismo evento forman una única cadena de middleware. El `next` de cada mod llama al hook del mod siguiente, y el último `next` llega al comportamiento propio de Claude Code. El primer mod es el más externo: ve el evento antes que los demás y el resultado después de ellos, y decide si los demás se ejecutan o no. Un mod posterior no puede impedir que uno anterior vea un evento.
285 312
286Claude Code ordena la cadena por dónde viene cada mod:313Claude Code ordena la cadena según el origen de cada mod:
287 314
2881. El guardia incorporado `sec-default@builtin`, un mod incorporado en Claude Code que `/plugin` enumera como `cc-plugin-sec-default`, donde [se carga](/docs/es/plugins/mods/admin#know-what-happens-by-default), mods que tu organización enumera en [`prependPlugins`](/docs/es/plugins/mods/admin#install-your-organizations-mods), y luego cualquier otro mod que cuente como de tu organización y no esté en `appendPlugins`3151. La protección integrada `sec-default@builtin`, un mod integrado en Claude Code que `/plugin` muestra como `cc-plugin-sec-default`, donde [se carga](/docs/es/plugins/mods/admin#know-what-happens-by-default), los mods que tu organización incluye en [`prependPlugins`](/docs/es/plugins/mods/admin#install-your-organizations-mods) y, luego, cualquier otro mod que se considere de tu organización y que no esté en `appendPlugins`
2892. Mods que instalas3162. Los mods que instalas
2903. Mods que tu organización enumera en `appendPlugins`3173. Los mods que tu organización incluye en `appendPlugins`
2914. Otros mods incorporados en Claude Code3184. Otros mods integrados en Claude Code
292 319
293Entre los mods que instalas, un mod se ejecuta antes que los mods que enumera bajo `dependencies` en su manifiesto. Dentro de un módulo, los hooks se ejecutan en el orden en que `register` llamó a `on`.320Entre los mods que instalas, un mod se ejecuta antes que los mods que incluye en `dependencies` en su manifiesto. Dentro de un mismo módulo, los hooks se ejecutan en el orden en que `register` llamó a `on`.
294 321
295<h4 id="where-settings-hooks-run-in-the-order">322<h4 id="where-settings-hooks-run-in-the-order">
296 Dónde se ejecutan los hooks de configuración en el orden323 Dónde se ubican los hooks de configuración en el orden
297</h4>324</h4>
298 325
299Los hooks `PreToolUse` configurados en archivos de configuración también se ejecutan durante una llamada de herramienta, en puntos fijos en la cadena de mods:326Los hooks `PreToolUse` configurados en archivos de configuración también se ejecutan durante una llamada a herramienta, en puntos fijos de la cadena de mods:
300 327
301* **Hooks `PreToolUse` de configuración administrada**: se ejecutan antes que el hook `tool.call` del primer mod, y un bloqueo de uno de ellos es final, por lo que ningún mod ve la llamada.328* **Hooks `PreToolUse` de la configuración administrada**: se ejecutan antes del hook `tool.call` del primer mod, y un bloqueo de uno de ellos es definitivo, así que ningún mod ve la llamada.
302* **Hooks `PreToolUse` de cada otro archivo de configuración y de `hooks/hooks.json` de plugins**: se ejecutan después de que el último mod llama a `next`, como parte del comportamiento propio de Claude Code. Un mod que responde `tool.call` sin llamar a `next` los mantiene de ejecutarse, y un mod que llama a `next` ve su decisión en el resultado que devuelve.329* **Hooks `PreToolUse` de cualquier otro archivo de configuración y del `hooks/hooks.json` de los plugins**: se ejecutan después de que el último mod llama a `next`, como parte del comportamiento propio de Claude Code. Un mod que responde a `tool.call` sin llamar a `next` impide que se ejecuten, y un mod que llama a `next` ve su decisión en el resultado que devuelve.
303 330
304[`tool.check`](/docs/es/plugins/mods/reference#tools) es el evento donde Claude Code decide si una llamada de herramienta puede ejecutarse. Se dispara después de esos hooks y las reglas de permisos han decidido, y `next(e)` se resuelve a su decisión. Un hook en `tool.check` puede devolver una decisión diferente, como `{ decision: 'allow' }`, por lo que puede aprobar una llamada que un hook en el segundo grupo bloqueó. [Extender permisos con hooks](/docs/es/permissions#extend-permissions-with-hooks) enumera qué decisiones se mantienen sobre un mod.331[`tool.check`](#approve-or-refuse-a-tool-call-before-the-user-is-asked) se activa después de que esos hooks y las reglas de permisos hayan decidido, así que un hook en él puede aprobar una llamada que un hook del segundo grupo bloqueó.
305 332
306<h3 id="handle-a-hook-that-fails">333<h3 id="handle-a-hook-that-fails">
307 Manejar un hook que falla334 Manejar un hook que falla
308</h3>335</h3>
309 336
310Un hook que falla no rompe la sesión, y puedes decidir qué sucede en su lugar. Cuando un hook sin un manejador `.catch` lanza una excepción, agota el tiempo o devuelve un resultado de forma incorrecta, lo que sucede después depende de si había llamado a `next`:337Un hook que falla no interrumpe la sesión, y puedes decidir qué sucede en su lugar. Cuando un hook sin un controlador `.catch` lanza una excepción, agota el tiempo de espera o devuelve un resultado con una forma incorrecta, lo que sucede a continuación depende de si había llamado a `next`:
311 338
312* **Falló antes de llamar a `next`**: Claude Code lo omite, y el siguiente manejador se ejecuta en su lugar339* **Falló antes de llamar a `next`**: Claude Code lo omite, y el siguiente controlador se ejecuta en su lugar
313* **Falló después de que `next` se resolvió**: ese resultado se mantiene, y nada se ejecuta una segunda vez340* **Falló después de que `next` se resolvió**: ese resultado se mantiene, y nada se ejecuta por segunda vez
314 341
315Una línea nombra el mod, el evento y la razón, como `my-mod: tool.call hook skipped: threw Error: boom`. Dónde lo lees depende de la sesión, como [Averigua por qué un mod no hace nada](/docs/es/plugins/mods/troubleshoot#find-out-why-a-mod-does-nothing) enumera. Un hook `ui.render` cuyo dibujo no valida se reporta de manera diferente, como [Construir un árbol a partir de elementos](/docs/es/plugins/mods/interface#build-a-tree-from-elements) describe.342Una línea indica el mod, el evento y el motivo, por ejemplo `my-mod: tool.call hook skipped: threw Error: boom`. Dónde la lees depende de la sesión, como se indica en [Averiguar por qué un mod no hace nada](/docs/es/plugins/mods/troubleshoot#find-out-why-a-mod-does-nothing). Un hook `ui.render` cuyo dibujo no se valida se informa de otra manera, como se describe en [Construir un árbol a partir de elementos](/docs/es/plugins/mods/interface#build-a-tree-from-elements).
316 343
317Para hacer que un hook que bloquea llamadas falle cerrado, añade un manejador de error `.catch` que responda en su lugar. Aquí, `guard` es tu función de hook:344Para que un hook que bloquea llamadas falle de forma cerrada, agrega un controlador de errores `.catch` que responda en su lugar. Aquí, `guard` es tu función de hook:
318 345
319```javascript theme={null}346```javascript theme={null}
320// on devuelve un registro, y .catch adjunta un manejador a ese hook347// on returns a registration, and .catch attaches a handler to that one hook
321on('tool.call', { tool: 'Bash' }, guard).catch(async ($, e, next) => {348on('tool.call', { tool: 'Bash' }, guard).catch(async ($, e, next) => {
322 // next.error.kind es 'throw' o 'timeout', que dice cómo falló guard349 // next.error.kind is 'throw' or 'timeout', which says how guard failed
323 return { deny: 'The command guard failed, so this command was not run: ' + next.error.kind }350 return { deny: 'The command guard failed, so this command was not run: ' + next.error.kind }
324})351})
325```352```
326 353
327Mientras `guard` funciona, el manejador nunca se ejecuta. Cuando `guard` lanza una excepción o agota el tiempo en una llamada Bash, Claude Code llama al manejador con el mismo evento. El manejador devuelve `{ deny }`, por lo que el comando no se ejecuta, y Claude lee el texto con `throw` o `timeout` al final. Sin el manejador, Claude Code omitería `guard` y ejecutaría el comando. El manejador tiene [un segundo](/docs/es/plugins/mods/reference#limits) para responder.354Mientras `guard` funciona, el controlador nunca se ejecuta. Cuando `guard` lanza una excepción o agota el tiempo de espera en una llamada a Bash, Claude Code llama al controlador con el mismo evento. El controlador devuelve `{ deny }`, así que el comando no se ejecuta, y Claude lee el texto con `throw` o `timeout` al final. Sin el controlador, Claude Code omitiría `guard` y ejecutaría el comando. El controlador tiene su propio [límite de tiempo](/docs/es/plugins/mods/reference#limits), más corto.
328 355
329<h2 id="next-steps">356<h2 id="next-steps">
330 Próximos pasos357 Próximos pasos
331</h2>358</h2>
332 359
333* [Usa la API de mods](/docs/es/plugins/mods/api): añade comandos y herramientas, llama a un modelo y ejecuta trabajo en un temporizador360* [Usa la API de mods](/docs/es/plugins/mods/api): agrega comandos y herramientas, llama a un modelo y ejecuta trabajo con un temporizador
334* [Dibuja en la interfaz](/docs/es/plugins/mods/interface): muestra lo que tus hooks recopilan en un panel o encima de la indicación361* [Dibuja en la interfaz](/docs/es/plugins/mods/interface): muestra lo que recopilan tus hooks en un panel o encima del prompt
335* [Prueba un mod](/docs/es/plugins/mods/test): dispara cualquiera de estos eventos desde una prueba362* [Prueba un mod](/docs/es/plugins/mods/test): dispara cualquiera de estos eventos desde una prueba
336* [Referencia de mods](/docs/es/plugins/mods/reference): cada evento, cada método de API de mods y los límites363* [Referencia de mods](/docs/es/plugins/mods/reference): cada evento, cada método de la API de mods y los límites