Loading...
    • Guía para desarrolladores
    • Referencia de API
    • MCP
    • Recursos
    • Notas de la versión
    Search...
    ⌘K
    Primeros pasos
    Introducción a ClaudeInicio rápido
    Modelos y precios
    Descripción general de modelosElegir un modeloNovedades en Claude 4.6Guía de migraciónModelos deprecadosPrecios
    Crear con Claude
    Descripción general de característicasUsar la API de MessagesManejar razones de paradaMejores prácticas de prompting
    Gestión de contexto
    Ventanas de contextoCompactaciónEdición de contexto
    Capacidades
    Almacenamiento en caché de promptsPensamiento extendidoPensamiento adaptativoEsfuerzoStreaming de MessagesProcesamiento por lotesCitasSoporte multilingüeConteo de tokensEmbeddingsVisiónSoporte de PDFAPI de FilesResultados de búsquedaSalidas estructuradas
    Herramientas
    Descripción generalCómo implementar el uso de herramientasStreaming de herramientas de grano finoHerramienta BashHerramienta de ejecución de códigoLlamada de herramientas programáticaHerramienta de uso de computadoraHerramienta de editor de textoHerramienta de búsqueda webHerramienta de búsqueda webHerramienta de memoriaHerramienta de búsqueda de herramientas
    Agent Skills
    Descripción generalInicio rápidoMejores prácticasSkills para empresasUsar Skills con la API
    Agent SDK
    Descripción generalInicio rápidoSDK de TypeScriptTypeScript V2 (vista previa)SDK de PythonGuía de migración
    Entrada de streamingTransmitir respuestas en tiempo realManejar razones de paradaManejar permisosAprobaciones de usuario e entradaControlar la ejecución con hooksGestión de sesionesPunto de control de archivosSalidas estructuradas en el SDKAlojar el Agent SDKDesplegar agentes de IA de forma seguraModificar prompts del sistemaMCP en el SDKHerramientas personalizadasSubagentes en el SDKComandos de barra en el SDKAgent Skills en el SDKRastrear costos y usoListas de tareasPlugins en el SDK
    MCP en la API
    Conector MCPServidores MCP remotos
    Claude en plataformas de terceros
    Amazon BedrockMicrosoft FoundryVertex AI
    Ingeniería de prompts
    Descripción generalGenerador de promptsUsar plantillas de promptsMejorador de promptsSer claro y directoUsar ejemplos (prompting multishot)Dejar que Claude piense (CoT)Usar etiquetas XMLDar a Claude un rol (prompts del sistema)Encadenar prompts complejosConsejos de contexto largoConsejos de pensamiento extendido
    Probar y evaluar
    Definir criterios de éxitoDesarrollar casos de pruebaUsar la herramienta de evaluaciónReducir latencia
    Fortalecer protecciones
    Reducir alucinacionesAumentar consistencia de salidaMitigar ataques de jailbreakRechazos de streamingReducir fuga de promptsMantener a Claude en personaje
    Administración y monitoreo
    Descripción general de Admin APIResidencia de datosEspacios de trabajoAPI de uso y costosAPI de Claude Code AnalyticsRetención de datos cero
    Console
    Log in
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...

    Solutions

    • AI agents
    • Code modernization
    • Coding
    • Customer support
    • Education
    • Financial services
    • Government
    • Life sciences

    Partners

    • Amazon Bedrock
    • Google Cloud's Vertex AI

    Learn

    • Blog
    • Catalog
    • Courses
    • Use cases
    • Connectors
    • Customer stories
    • Engineering at Anthropic
    • Events
    • Powered by Claude
    • Service partners
    • Startups program

    Company

    • Anthropic
    • Careers
    • Economic Futures
    • Research
    • News
    • Responsible Scaling Policy
    • Security and compliance
    • Transparency

    Learn

    • Blog
    • Catalog
    • Courses
    • Use cases
    • Connectors
    • Customer stories
    • Engineering at Anthropic
    • Events
    • Powered by Claude
    • Service partners
    • Startups program

    Help and security

    • Availability
    • Status
    • Support
    • Discord

    Terms and policies

    • Privacy policy
    • Responsible disclosure policy
    • Terms of service: Commercial
    • Terms of service: Consumer
    • Usage policy
    Guías

    Interceptar y controlar el comportamiento del agente con hooks

    Interceptar y personalizar el comportamiento del agente en puntos clave de ejecución con hooks

    Was this page helpful?

    • Hooks disponibles
    • Casos de uso comunes
    • Configurar hooks
    • Matchers
    • Entradas de función de devolución de llamada
    • Datos de entrada
    • Salidas de devolución de llamada
    • Manejar escenarios avanzados
    • Encadenar múltiples hooks
    • Matchers específicos de herramienta con regex
    • Rastrear actividad de subagentes
    • Operaciones asincrónicas en hooks
    • Enviar notificaciones (solo TypeScript)
    • Solucionar problemas comunes
    • Hook no se dispara
    • Matcher no filtra como se esperaba
    • Tiempo de espera del hook
    • Herramienta bloqueada inesperadamente
    • Entrada modificada no aplicada
    • Hooks de sesión no disponibles
    • Solicitudes de permiso de subagente multiplicándose
    • Bucles recursivos de hooks con subagentes
    • systemMessage no aparece en la salida
    • Aprende más

    Los hooks te permiten interceptar la ejecución del agente en puntos clave para agregar validación, registro, controles de seguridad o lógica personalizada. Con hooks, puedes:

    • Bloquear operaciones peligrosas antes de que se ejecuten, como comandos de shell destructivos o acceso a archivos no autorizado
    • Registrar y auditar cada llamada de herramienta para cumplimiento normativo, depuración o análisis
    • Transformar entradas y salidas para desinfectar datos, inyectar credenciales o redirigir rutas de archivos
    • Requerir aprobación humana para acciones sensibles como escrituras en bases de datos o llamadas a API
    • Rastrear el ciclo de vida de la sesión para gestionar estado, limpiar recursos o enviar notificaciones

    Un hook tiene dos partes:

    1. La función de devolución de llamada: la lógica que se ejecuta cuando se dispara el hook
    2. La configuración del hook: le dice al SDK qué evento enganchar (como PreToolUse) y qué herramientas coinciden

    El siguiente ejemplo bloquea al agente de modificar archivos .env. Primero, define una devolución de llamada que verifica la ruta del archivo, luego pásala a query() para ejecutarla antes de cualquier llamada de herramienta Write o Edit:

    Este es un hook PreToolUse. Se ejecuta antes de que se ejecute la herramienta y puede bloquear u permitir operaciones basadas en tu lógica. El resto de esta guía cubre todos los hooks disponibles, sus opciones de configuración y patrones para casos de uso comunes.

    Hooks disponibles

    El SDK proporciona hooks para diferentes etapas de la ejecución del agente. Algunos hooks están disponibles en ambos SDK, mientras que otros son solo de TypeScript porque el SDK de Python no los admite.

    Hook EventPython SDKTypeScript SDKWhat triggers itExample use case
    PreToolUseYesYesTool call request (can block or modify)Block dangerous shell commands
    PostToolUseYesYesTool execution resultLog all file changes to audit trail
    PostToolUseFailureNoYesTool execution failureHandle or log tool errors
    UserPromptSubmitYesYesUser prompt submissionInject additional context into prompts

    Casos de uso comunes

    Los hooks son lo suficientemente flexibles para manejar muchos escenarios diferentes. Aquí hay algunos de los patrones más comunes organizados por categoría.

    Configurar hooks

    Para configurar un hook para tu agente, pasa el hook en el parámetro options.hooks al llamar a query():

    async for message in query(
        prompt="Your prompt",
        options=ClaudeAgentOptions(
            hooks={
                'PreToolUse': [HookMatcher(matcher='Bash', hooks=[my_callback])]
            }
        )
    ):
        print(message)

    La opción hooks es un diccionario (Python) u objeto (TypeScript) donde:

    • Las claves son nombres de eventos de hook (por ejemplo, 'PreToolUse', 'PostToolUse', 'Stop')
    • Los valores son matrices de matchers, cada una conteniendo un patrón de filtro opcional y tus funciones de devolución de llamada

    Tus funciones de devolución de llamada de hook reciben datos de entrada sobre el evento y devuelven una respuesta para que el agente sepa si permitir, bloquear o modificar la operación.

    Matchers

    Usa matchers para filtrar qué herramientas disparan tus devoluciones de llamada:

    OptionTypeDefaultDescription
    matcherstringundefinedRegex pattern to match tool names. Built-in tools include Bash, Read, Write, Edit, Glob, Grep, WebFetch, Task, and others. MCP tools use the pattern mcp__<server>__<action>.
    hooksHookCallback[]

    Usa el patrón matcher para dirigirse a herramientas específicas siempre que sea posible. Un matcher con 'Bash' solo se ejecuta para comandos Bash, mientras que omitir el patrón ejecuta tus devoluciones de llamada para cada llamada de herramienta. Ten en cuenta que los matchers solo filtran por nombre de herramienta, no por rutas de archivo u otros argumentos—para filtrar por ruta de archivo, verifica tool_input.file_path dentro de tu devolución de llamada.

    Los matchers solo se aplican a hooks basados en herramientas (PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest). Para hooks de ciclo de vida como Stop, SessionStart y Notification, los matchers se ignoran y el hook se dispara para todos los eventos de ese tipo.

    Discovering tool names: Check the tools array in the initial system message when your session starts, or add a hook without a matcher to log all tool calls.

    MCP tool naming: MCP tools always start with mcp__ followed by the server name and action: mcp__<server>__<action>. For example, if you configure a server named playwright, its tools will be named mcp__playwright__browser_screenshot, mcp__playwright__browser_click, etc. The server name comes from the key you use in the mcpServers configuration.

    Este ejemplo usa un matcher para ejecutar un hook solo para herramientas que modifican archivos cuando se dispara el evento PreToolUse:

    options = ClaudeAgentOptions(
        hooks={
            'PreToolUse': [
                HookMatcher(matcher='Write|Edit', hooks=[validate_file_path])
            ]
        }
    )

    Entradas de función de devolución de llamada

    Cada devolución de llamada de hook recibe tres argumentos:

    1. Datos de entrada (dict / HookInput): Detalles del evento. Consulta datos de entrada para los campos
    2. ID de uso de herramienta (str | None / string | null): Correlaciona eventos PreToolUse y PostToolUse
    3. Contexto (HookContext): En TypeScript, contiene una propiedad signal (AbortSignal) para cancelación. Pasa esto a operaciones asincrónicas como fetch() para que se cancelen automáticamente si el hook agota el tiempo. En Python, este argumento está reservado para uso futuro.

    Datos de entrada

    El primer argumento de tu devolución de llamada de hook contiene información sobre el evento. Los nombres de campo son idénticos en todos los SDK (ambos usan snake_case).

    Campos comunes presentes en todos los tipos de hook:

    FieldTypeDescription
    hook_event_namestringThe hook type (PreToolUse, PostToolUse, etc.)
    session_idstringCurrent session identifier
    transcript_pathstringPath to the conversation transcript
    cwdstringCurrent working directory

    Campos específicos del hook varían según el tipo de hook. Los elementos marcados TS solo están disponibles en el SDK de TypeScript:

    FieldTypeDescriptionHooks
    tool_namestringName of the tool being calledPreToolUse, PostToolUse, PostToolUseFailureTS, PermissionRequestTS
    tool_inputobjectArguments passed to the toolPreToolUse, PostToolUse, PostToolUseFailureTS, PermissionRequestTS
    tool_responseanyResult returned from tool executionPostToolUse
    errorstring

    El código siguiente define una devolución de llamada de hook que usa tool_name y tool_input para registrar detalles sobre cada llamada de herramienta:

    Salidas de devolución de llamada

    Tu función de devolución de llamada devuelve un objeto que le dice al SDK cómo proceder. Devuelve un objeto vacío {} para permitir la operación sin cambios. Para bloquear, modificar o agregar contexto a la operación, devuelve un objeto con un campo hookSpecificOutput que contiene tu decisión.

    Campos de nivel superior (fuera de hookSpecificOutput):

    FieldTypeDescription
    continuebooleanWhether the agent should continue after this hook (default: true)
    stopReasonstringMessage shown when continue is false
    suppressOutputbooleanHide stdout from the transcript (default: false)
    systemMessagestring

    Campos dentro de hookSpecificOutput:

    FieldTypeHooksDescription
    hookEventNamestringAllRequired. Use input.hook_event_name to match the current event
    permissionDecision'allow' | 'deny' | 'ask'PreToolUseControls whether the tool executes
    permissionDecisionReasonstringPreToolUseExplanation shown to Claude for the decision

    Este ejemplo bloquea operaciones de escritura en el directorio /etc mientras inyecta un mensaje del sistema para recordarle a Claude sobre prácticas seguras de archivos:

    Flujo de decisión de permisos

    Cuando se aplican múltiples hooks o reglas de permisos, el SDK los evalúa en este orden:

    1. Las reglas de negación se verifican primero (cualquier coincidencia = negación inmediata).
    2. Las reglas de pregunta se verifican en segundo lugar.
    3. Las reglas de permiso se verifican en tercer lugar.
    4. Por defecto a Preguntar si nada coincide.

    Si algún hook devuelve deny, la operación se bloquea—otros hooks que devuelven allow no lo anularán.

    Bloquear una herramienta

    Devuelve una decisión de negación para evitar la ejecución de la herramienta:

    Modificar entrada de herramienta

    Devuelve entrada actualizada para cambiar lo que recibe la herramienta:

    When using updatedInput, you must also include permissionDecision. Always return a new object rather than mutating the original tool_input.

    Agregar un mensaje del sistema

    Inyecta contexto en la conversación:

    async def add_security_reminder(input_data, tool_use_id, context):
        return {
            'systemMessage': 'Remember to follow security best practices.'
        }

    Aprobar automáticamente herramientas específicas

    Omite solicitudes de permiso para herramientas de confianza. Esto es útil cuando deseas que ciertas operaciones se ejecuten sin confirmación del usuario:

    The permissionDecision field accepts three values: 'allow' (auto-approve), 'deny' (block), or 'ask' (prompt for confirmation).

    Manejar escenarios avanzados

    Estos patrones te ayudan a construir sistemas de hooks más sofisticados para casos de uso complejos.

    Encadenar múltiples hooks

    Los hooks se ejecutan en el orden en que aparecen en la matriz. Mantén cada hook enfocado en una única responsabilidad y encadena múltiples hooks para lógica compleja. Este ejemplo ejecuta los cuatro hooks para cada llamada de herramienta (sin matcher especificado):

    Matchers específicos de herramienta con regex

    Usa patrones regex para coincidir con múltiples herramientas:

    Matchers only match tool names, not file paths or other arguments. To filter by file path, check tool_input.file_path inside your hook callback.

    Rastrear actividad de subagentes

    Usa hooks SubagentStop para monitorear la finalización de subagentes. El tool_use_id ayuda a correlacionar llamadas de agente padre con sus subagentes:

    Operaciones asincrónicas en hooks

    Los hooks pueden realizar operaciones asincrónicas como solicitudes HTTP. Maneja errores correctamente capturando excepciones en lugar de lanzarlas. En TypeScript, pasa el signal a fetch() para que la solicitud se cancele si el hook agota el tiempo:

    Enviar notificaciones (solo TypeScript)

    Usa hooks Notification para recibir actualizaciones de estado del agente y reenviarlas a servicios externos como Slack o paneles de monitoreo:

    TypeScript
    import { query, HookCallback, NotificationHookInput } from "@anthropic-ai/claude-agent-sdk";
    
    const notificationHandler: HookCallback = async (input, toolUseID, { signal }) => {
      const notification = input as NotificationHookInput;
    
      await fetch('https://hooks.slack.com/services/YOUR/WEBHOOK/URL', {
        method: 'POST',
        body: JSON.stringify({
          text: `Agent status: ${notification.message}`
        }),
        signal
      });
    
      return {};
    };
    
    for await (const message of query({
      prompt: "Analyze this codebase",
      options: {
        hooks: {
          Notification: [{ hooks: [notificationHandler] }]
        }
      }
    })) {
      console.log(message);
    }

    Solucionar problemas comunes

    Esta sección cubre problemas comunes y cómo resolverlos.

    Hook no se dispara

    • Verifica que el nombre del evento del hook sea correcto y sensible a mayúsculas (PreToolUse, no preToolUse)
    • Comprueba que tu patrón de matcher coincida exactamente con el nombre de la herramienta
    • Asegúrate de que el hook esté bajo el tipo de evento correcto en options.hooks
    • Para hooks SubagentStop, Stop, SessionStart, SessionEnd y Notification, los matchers se ignoran. Estos hooks se disparan para todos los eventos de ese tipo.
    • Los hooks pueden no dispararse cuando el agente alcanza el límite de max_turns porque la sesión termina antes de que los hooks puedan ejecutarse

    Matcher no filtra como se esperaba

    Los matchers solo coinciden con nombres de herramientas, no con rutas de archivo u otros argumentos. Para filtrar por ruta de archivo, verifica tool_input.file_path dentro de tu hook:

    const myHook: HookCallback = async (input, toolUseID, { signal }) => {
      const preInput = input as PreToolUseHookInput;
      const filePath = preInput.tool_input?.file_path as string;
      if (!filePath?.endsWith('.md')) return {};  // Skip non-markdown files
      // Process markdown files...
    };

    Tiempo de espera del hook

    • Aumenta el valor de timeout en la configuración de HookMatcher
    • Usa el AbortSignal del tercer argumento de devolución de llamada para manejar la cancelación correctamente en TypeScript

    Herramienta bloqueada inesperadamente

    • Comprueba todos los hooks PreToolUse para devoluciones de permissionDecision: 'deny'
    • Agrega registro a tus hooks para ver qué permissionDecisionReason están devolviendo
    • Verifica que los patrones de matcher no sean demasiado amplios (un matcher vacío coincide con todas las herramientas)

    Entrada modificada no aplicada

    • Asegúrate de que updatedInput esté dentro de hookSpecificOutput, no en el nivel superior:

      return {
        hookSpecificOutput: {
          hookEventName: input.hook_event_name,
          permissionDecision: 'allow',
          updatedInput: { command: 'new command' }
        }
      };
    • También debes devolver permissionDecision: 'allow' para que la modificación de entrada surta efecto

    Hooks de sesión no disponibles

    Los hooks SessionStart, SessionEnd y Notification solo están disponibles en el SDK de TypeScript. El SDK de Python no admite estos eventos debido a limitaciones de configuración.

    Solicitudes de permiso de subagente multiplicándose

    Al generar múltiples subagentes, cada uno puede solicitar permisos por separado. Los subagentes no heredan automáticamente los permisos del agente padre. Para evitar solicitudes repetidas, usa hooks PreToolUse para aprobar automáticamente herramientas específicas, o configura reglas de permisos que se apliquen a sesiones de subagentes.

    Bucles recursivos de hooks con subagentes

    Un hook UserPromptSubmit que genera subagentes puede crear bucles infinitos si esos subagentes disparan el mismo hook. Para evitar esto:

    • Verifica un indicador de subagente en la entrada del hook antes de generar
    • Usa el campo parent_tool_use_id para detectar si ya estás en un contexto de subagente
    • Limita los hooks para que solo se ejecuten en la sesión del agente de nivel superior

    systemMessage no aparece en la salida

    El campo systemMessage agrega contexto a la conversación que el modelo ve, pero puede no aparecer en todos los modos de salida del SDK. Si necesitas exponer decisiones de hooks a tu aplicación, regístralas por separado o usa un canal de salida dedicado.

    Aprende más

    • Permissions: control what your agent can do
    • Custom Tools: build tools to extend agent capabilities
    • TypeScript SDK Reference
    • Python SDK Reference
    import asyncio
    from claude_agent_sdk import query, ClaudeAgentOptions, HookMatcher
    
    # Define a hook callback that receives tool call details
    async def protect_env_files(input_data, tool_use_id, context):
        # Extract the file path from the tool's input arguments
        file_path = input_data['tool_input'].get('file_path', '')
        file_name = file_path.split('/')[-1]
    
        # Block the operation if targeting a .env file
        if file_name == '.env':
            return {
                'hookSpecificOutput': {
                    'hookEventName': input_data['hook_event_name'],
                    'permissionDecision': 'deny',
                    'permissionDecisionReason': 'Cannot modify .env files'
                }
            }
    
        # Return empty object to allow the operation
        return {}
    
    async def main():
        async for message in query(
            prompt="Update the database configuration",
            options=ClaudeAgentOptions(
                hooks={
                    # Register the hook for PreToolUse events
                    # The matcher filters to only Write and Edit tool calls
                    'PreToolUse': [HookMatcher(matcher='Write|Edit', hooks=[protect_env_files])]
                }
            )
        ):
            print(message)
    
    asyncio.run(main())
    StopYesYesAgent execution stopSave session state before exit
    SubagentStartNoYesSubagent initializationTrack parallel task spawning
    SubagentStopYesYesSubagent completionAggregate results from parallel tasks
    PreCompactYesYesConversation compaction requestArchive full transcript before summarizing
    PermissionRequestNoYesPermission dialog would be displayedCustom permission handling
    SessionStartNoYesSession initializationInitialize logging and telemetry
    SessionEndNoYesSession terminationClean up temporary resources
    NotificationNoYesAgent status messagesSend agent status updates to Slack or PagerDuty
    -
    Required. Array of callback functions to execute when the pattern matches
    timeoutnumber60Timeout in seconds; increase for hooks that make external API calls
    Error message from tool execution failure
    PostToolUseFailureTS
    is_interruptbooleanWhether the failure was caused by an interruptPostToolUseFailureTS
    promptstringThe user's prompt textUserPromptSubmit
    stop_hook_activebooleanWhether a stop hook is currently processingStop, SubagentStop
    agent_idstringUnique identifier for the subagentSubagentStartTS, SubagentStopTS
    agent_typestringType/role of the subagentSubagentStartTS
    agent_transcript_pathstringPath to the subagent's conversation transcriptSubagentStopTS
    triggerstringWhat triggered compaction: manual or autoPreCompact
    custom_instructionsstringCustom instructions provided for compactionPreCompact
    permission_suggestionsarraySuggested permission updates for the toolPermissionRequestTS
    sourcestringHow the session started: startup, resume, clear, or compactSessionStartTS
    reasonstringWhy the session ended: clear, logout, prompt_input_exit, bypass_permissions_disabled, or otherSessionEndTS
    messagestringStatus message from the agentNotificationTS
    notification_typestringType of notification: permission_prompt, idle_prompt, auth_success, or elicitation_dialogNotificationTS
    titlestringOptional title set by the agentNotificationTS
    async def log_tool_calls(input_data, tool_use_id, context):
        if input_data['hook_event_name'] == 'PreToolUse':
            print(f"Tool: {input_data['tool_name']}")
            print(f"Input: {input_data['tool_input']}")
        return {}
    Message injected into the conversation for Claude to see
    updatedInput
    object
    PreToolUse
    Modified tool input (requires permissionDecision: 'allow')
    additionalContextstringPreToolUse, PostToolUse, UserPromptSubmit, SessionStartTS, SubagentStartTSContext added to the conversation
    async def block_etc_writes(input_data, tool_use_id, context):
        file_path = input_data['tool_input'].get('file_path', '')
    
        if file_path.startswith('/etc'):
            return {
                # Top-level field: inject guidance into the conversation
                'systemMessage': 'Remember: system directories like /etc are protected.',
                # hookSpecificOutput: block the operation
                'hookSpecificOutput': {
                    'hookEventName': input_data['hook_event_name'],
                    'permissionDecision': 'deny',
                    'permissionDecisionReason': 'Writing to /etc is not allowed'
                }
            }
        return {}
    async def block_dangerous_commands(input_data, tool_use_id, context):
        if input_data['hook_event_name'] != 'PreToolUse':
            return {}
    
        command = input_data['tool_input'].get('command', '')
    
        if 'rm -rf /' in command:
            return {
                'hookSpecificOutput': {
                    'hookEventName': input_data['hook_event_name'],
                    'permissionDecision': 'deny',
                    'permissionDecisionReason': 'Dangerous command blocked: rm -rf /'
                }
            }
        return {}
    async def redirect_to_sandbox(input_data, tool_use_id, context):
        if input_data['hook_event_name'] != 'PreToolUse':
            return {}
    
        if input_data['tool_name'] == 'Write':
            original_path = input_data['tool_input'].get('file_path', '')
            return {
                'hookSpecificOutput': {
                    'hookEventName': input_data['hook_event_name'],
                    'permissionDecision': 'allow',
                    'updatedInput': {
                        **input_data['tool_input'],
                        'file_path': f'/sandbox{original_path}'
                    }
                }
            }
        return {}
    async def auto_approve_read_only(input_data, tool_use_id, context):
        if input_data['hook_event_name'] != 'PreToolUse':
            return {}
    
        read_only_tools = ['Read', 'Glob', 'Grep', 'LS']
        if input_data['tool_name'] in read_only_tools:
            return {
                'hookSpecificOutput': {
                    'hookEventName': input_data['hook_event_name'],
                    'permissionDecision': 'allow',
                    'permissionDecisionReason': 'Read-only tool auto-approved'
                }
            }
        return {}
    options = ClaudeAgentOptions(
        hooks={
            'PreToolUse': [
                HookMatcher(hooks=[rate_limiter]),        # First: check rate limits
                HookMatcher(hooks=[authorization_check]), # Second: verify permissions
                HookMatcher(hooks=[input_sanitizer]),     # Third: sanitize inputs
                HookMatcher(hooks=[audit_logger])         # Last: log the action
            ]
        }
    )
    options = ClaudeAgentOptions(
        hooks={
            'PreToolUse': [
                # Match file modification tools
                HookMatcher(matcher='Write|Edit|Delete', hooks=[file_security_hook]),
    
                # Match all MCP tools
                HookMatcher(matcher='^mcp__', hooks=[mcp_audit_hook]),
    
                # Match everything (no matcher)
                HookMatcher(hooks=[global_logger])
            ]
        }
    )
    async def subagent_tracker(input_data, tool_use_id, context):
        if input_data['hook_event_name'] == 'SubagentStop':
            print(f"[SUBAGENT] Completed")
            print(f"  Tool use ID: {tool_use_id}")
            print(f"  Stop hook active: {input_data.get('stop_hook_active')}")
        return {}
    
    options = ClaudeAgentOptions(
        hooks={
            'SubagentStop': [HookMatcher(hooks=[subagent_tracker])]
        }
    )
    import aiohttp
    from datetime import datetime
    
    async def webhook_notifier(input_data, tool_use_id, context):
        if input_data['hook_event_name'] != 'PostToolUse':
            return {}
    
        try:
            async with aiohttp.ClientSession() as session:
                await session.post(
                    'https://api.example.com/webhook',
                    json={
                        'tool': input_data['tool_name'],
                        'timestamp': datetime.now().isoformat()
                    }
                )
        except Exception as e:
            print(f'Webhook request failed: {e}')
    
        return {}
  1. Incluye hookEventName en hookSpecificOutput para identificar qué tipo de hook es la salida