Loading...
    • Guia do Desenvolvedor
    • Referência da API
    • MCP
    • Recursos
    • Notas de lançamento
    Search...
    ⌘K
    Primeiros passos
    Introdução ao ClaudeInício rápido
    Modelos e preços
    Visão geral dos modelosEscolhendo um modeloNovidades no Claude 4.5Migrando para Claude 4.5Descontinuação de modelosPreços
    Construir com Claude
    Visão geral de recursosUsando a API MessagesJanelas de contextoMelhores práticas de prompting
    Capacidades
    Cache de promptsEdição de contextoPensamento estendidoEsforçoStreaming de mensagensProcessamento em loteCitaçõesSuporte multilíngueContagem de tokensEmbeddingsVisãoSuporte a PDFAPI de arquivosResultados de buscaSaídas estruturadas
    Ferramentas
    Visão geralComo implementar o uso de ferramentasStreaming de ferramentas granularFerramenta BashFerramenta de execução de códigoChamada de ferramentas programáticaFerramenta de uso de computadorFerramenta de editor de textoFerramenta de busca na webFerramenta de busca na webFerramenta de memóriaFerramenta de busca de ferramentas
    Habilidades de agente
    Visão geralInício rápidoMelhores práticasUsando habilidades com a API
    SDK de agente
    Visão geralInício rápidoSDK TypeScriptTypeScript V2 (prévia)SDK PythonGuia de migração
    Entrada de streamingTratamento de permissõesControlar execução com hooksGerenciamento de sessãoSaídas estruturadas no SDKHospedando o SDK de agenteImplantação segura de agentes de IAModificando prompts do sistemaMCP no SDKFerramentas personalizadasSubagentos no SDKComandos de barra no SDKHabilidades de agente no SDKRastreando custos e usoListas de tarefasPlugins no SDK
    MCP na API
    Conector MCPServidores MCP remotos
    Claude em plataformas de terceiros
    Amazon BedrockMicrosoft FoundryVertex AI
    Engenharia de prompts
    Visão geralGerador de promptsUsar modelos de promptsMelhorador de promptsSeja claro e diretoUse exemplos (prompting multishot)Deixe Claude pensar (CoT)Use tags XMLDê um papel ao Claude (prompts do sistema)Preencha previamente a resposta do ClaudeEncadeie prompts complexosDicas de contexto longoDicas de pensamento estendido
    Testar e avaliar
    Definir critérios de sucessoDesenvolver casos de testeUsando a ferramenta de avaliaçãoReduzindo latência
    Fortalecer proteções
    Reduzir alucinaçõesAumentar consistência de saídaMitigar jailbreaksRecusas de streamingReduzir vazamento de promptManter Claude em personagem
    Administração e monitoramento
    Visão geral da API de administraçãoAPI de uso e custoAPI de análise de código Claude
    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
    Guias

    Interceptar e controlar o comportamento do agente com hooks

    Interceptar e personalizar o comportamento do agente em pontos-chave de execução com hooks

    Hooks permitem que você intercepte a execução do agente em pontos-chave para adicionar validação, logging, controles de segurança ou lógica personalizada. Com hooks, você pode:

    • Bloquear operações perigosas antes de serem executadas, como comandos shell destrutivos ou acesso a arquivos não autorizado
    • Registrar e auditar cada chamada de ferramenta para conformidade, depuração ou análise
    • Transformar entradas e saídas para sanitizar dados, injetar credenciais ou redirecionar caminhos de arquivo
    • Exigir aprovação humana para ações sensíveis como gravações em banco de dados ou chamadas de API
    • Rastrear ciclo de vida da sessão para gerenciar estado, limpar recursos ou enviar notificações

    Um hook tem duas partes:

    1. A função de callback: a lógica que é executada quando o hook dispara
    2. A configuração do hook: informa ao SDK qual evento conectar (como PreToolUse) e quais ferramentas corresponder

    O exemplo a seguir bloqueia o agente de modificar arquivos .env. Primeiro, defina um callback que verifica o caminho do arquivo, depois passe-o para query() para executar antes de qualquer chamada de ferramenta Write ou Edit:

    Este é um hook PreToolUse. Ele é executado antes da ferramenta ser executada e pode bloquear ou permitir operações com base em sua lógica. O restante deste guia cobre todos os hooks disponíveis, suas opções de configuração e padrões para casos de uso comuns.

    Hooks disponíveis

    O SDK fornece hooks para diferentes estágios de execução do agente. Alguns hooks estão disponíveis em ambos os SDKs, enquanto outros são apenas para TypeScript porque o SDK Python não os suporta.

    Hook EventPython SDKTypeScript SDKO que disparaCaso de uso de exemplo
    PreToolUseSimSimSolicitação de chamada de ferramenta (pode bloquear ou modificar)Bloquear comandos shell perigosos
    PostToolUseSimSimResultado da execução da ferramentaRegistrar todas as alterações de arquivo na trilha de auditoria
    PostToolUseFailureNãoSimFalha na execução da ferramentaLidar ou registrar erros de ferramenta
    UserPromptSubmitSimSimEnvio de prompt do usuário

    Casos de uso comuns

    Hooks são flexíveis o suficiente para lidar com muitos cenários diferentes. Aqui estão alguns dos padrões mais comuns organizados por categoria.

    Configurar hooks

    Para configurar um hook para seu agente, passe o hook no parâmetro options.hooks ao chamar query():

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

    A opção hooks é um dicionário (Python) ou objeto (TypeScript) onde:

    • Chaves são nomes de eventos de hook (por exemplo, 'PreToolUse', 'PostToolUse', 'Stop')
    • Valores são arrays de matchers, cada um contendo um padrão de filtro opcional e suas funções de callback

    Suas funções de callback de hook recebem dados de entrada sobre o evento e retornam uma resposta para que o agente saiba permitir, bloquear ou modificar a operação.

    Matchers

    Use matchers para filtrar quais ferramentas disparam seus callbacks:

    OpçãoTipoPadrãoDescrição
    matcherstringundefinedPadrão regex para corresponder nomes de ferramentas. As ferramentas integradas incluem Bash, Read, Write, Edit, Glob, Grep, WebFetch, Task e outras. As ferramentas MCP usam o padrão mcp__<server>__<action>.
    hooksHookCallback[]

    Use o padrão matcher para direcionar ferramentas específicas sempre que possível. Um matcher com 'Bash' é executado apenas para comandos Bash, enquanto omitir o padrão executa seus callbacks para cada chamada de ferramenta. Observe que matchers apenas filtram por nome da ferramenta, não por caminhos de arquivo ou outros argumentos—para filtrar por caminho de arquivo, verifique tool_input.file_path dentro de seu callback.

    Matchers se aplicam apenas a hooks baseados em ferramentas (PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest). Para hooks de ciclo de vida como Stop, SessionStart e Notification, matchers são ignorados e o hook dispara para todos os eventos desse tipo.

    Descobrindo nomes de ferramentas: Verifique o array tools na mensagem do sistema inicial quando sua sessão começar, ou adicione um hook sem um matcher para registrar todas as chamadas de ferramenta.

    Nomenclatura de ferramentas MCP: As ferramentas MCP sempre começam com mcp__ seguidas pelo nome do servidor e ação: mcp__<server>__<action>. Por exemplo, se você configurar um servidor chamado playwright, suas ferramentas serão nomeadas mcp__playwright__browser_screenshot, mcp__playwright__browser_click, etc. O nome do servidor vem da chave que você usa na configuração mcpServers.

    Este exemplo usa um matcher para executar um hook apenas para ferramentas que modificam arquivos quando o evento PreToolUse dispara:

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

    Entradas de função de callback

    Cada callback de hook recebe três argumentos:

    1. Dados de entrada (dict / HookInput): Detalhes do evento. Veja dados de entrada para campos
    2. ID de uso de ferramenta (str | None / string | null): Correlacionar eventos PreToolUse e PostToolUse
    3. Contexto (HookContext): Em TypeScript, contém uma propriedade signal (AbortSignal) para cancelamento. Passe isso para operações assíncronas como fetch() para que elas se cancelem automaticamente se o hook expirar. Em Python, este argumento é reservado para uso futuro.

    Dados de entrada

    O primeiro argumento para seu callback de hook contém informações sobre o evento. Os nomes dos campos são idênticos entre SDKs (ambos usam snake_case).

    Campos comuns presentes em todos os tipos de hook:

    CampoTipoDescrição
    hook_event_namestringO tipo de hook (PreToolUse, PostToolUse, etc.)
    session_idstringIdentificador de sessão atual
    transcript_pathstringCaminho para a transcrição da conversa
    cwdstringDiretório de trabalho atual

    Campos específicos do hook variam por tipo de hook. Itens marcados TS estão disponíveis apenas no SDK TypeScript:

    CampoTipoDescriçãoHooks
    tool_namestringNome da ferramenta sendo chamadaPreToolUse, PostToolUse, PostToolUseFailureTS, PermissionRequestTS
    tool_inputobjectArgumentos passados para a ferramentaPreToolUse, PostToolUse, PostToolUseFailureTS, PermissionRequestTS
    tool_responseanyResultado retornado da execução da ferramentaPostToolUse
    errorstring

    O código abaixo define um callback de hook que usa tool_name e tool_input para registrar detalhes sobre cada chamada de ferramenta:

    Saídas de callback

    Sua função de callback retorna um objeto que informa ao SDK como proceder. Retorne um objeto vazio {} para permitir a operação sem alterações. Para bloquear, modificar ou adicionar contexto à operação, retorne um objeto com um campo hookSpecificOutput contendo sua decisão.

    Campos de nível superior (fora de hookSpecificOutput):

    CampoTipoDescrição
    continuebooleanSe o agente deve continuar após este hook (padrão: true)
    stopReasonstringMensagem mostrada quando continue é false
    suppressOutputbooleanOcultar stdout da transcrição (padrão: false)
    systemMessagestring

    Campos dentro de hookSpecificOutput:

    CampoTipoHooksDescrição
    hookEventNamestringTodosObrigatório. Use input.hook_event_name para corresponder ao evento atual
    permissionDecision'allow' | 'deny' | 'ask'PreToolUseControla se a ferramenta é executada
    permissionDecisionReasonstringPreToolUseExplicação mostrada a Claude para a decisão
    updatedInput

    Este exemplo bloqueia operações de gravação no diretório /etc enquanto injeta uma mensagem do sistema para lembrar Claude sobre práticas seguras de arquivo:

    Fluxo de decisão de permissão

    Quando múltiplos hooks ou regras de permissão se aplicam, o SDK os avalia nesta ordem:

    1. Regras de negação são verificadas primeiro (qualquer correspondência = negação imediata).
    2. Regras de pergunta são verificadas em segundo lugar.
    3. Regras de permissão são verificadas em terceiro lugar.
    4. Padrão para pergunta se nada corresponder.

    Se qualquer hook retornar deny, a operação é bloqueada—outros hooks retornando allow não a substituirão.

    Bloquear uma ferramenta

    Retorne uma decisão de negação para impedir a execução da ferramenta:

    Modificar entrada de ferramenta

    Retorne entrada atualizada para alterar o que a ferramenta recebe:

    Ao usar updatedInput, você também deve incluir permissionDecision. Sempre retorne um novo objeto em vez de mutar o tool_input original.

    Adicionar uma mensagem do sistema

    Injetar contexto na conversa:

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

    Aprovar automaticamente ferramentas específicas

    Contornar prompts de permissão para ferramentas confiáveis. Isso é útil quando você quer que certas operações sejam executadas sem confirmação do usuário:

    O campo permissionDecision aceita três valores: 'allow' (aprovar automaticamente), 'deny' (bloquear) ou 'ask' (solicitar confirmação).

    Lidar com cenários avançados

    Esses padrões ajudam você a construir sistemas de hook mais sofisticados para casos de uso complexos.

    Encadeando múltiplos hooks

    Hooks são executados na ordem em que aparecem no array. Mantenha cada hook focado em uma única responsabilidade e encadeie múltiplos hooks para lógica complexa. Este exemplo executa todos os quatro hooks para cada chamada de ferramenta (nenhum matcher especificado):

    Matchers de ferramentas específicas com regex

    Use padrões regex para corresponder múltiplas ferramentas:

    Matchers apenas correspondem nomes de ferramentas, não caminhos de arquivo ou outros argumentos. Para filtrar por caminho de arquivo, verifique tool_input.file_path dentro de seu callback de hook.

    Rastreando atividade de subagente

    Use hooks SubagentStop para monitorar a conclusão de subagente. O tool_use_id ajuda a correlacionar chamadas de agente pai com seus subagentes:

    Operações assíncronas em hooks

    Hooks podem realizar operações assíncronas como requisições HTTP. Lidar com erros graciosamente capturando exceções em vez de lançá-las. Em TypeScript, passe o signal para fetch() para que a requisição seja cancelada se o hook expirar:

    Enviando notificações (apenas TypeScript)

    Use hooks Notification para receber atualizações de status do agente e encaminhá-las para serviços externos como Slack ou painéis de monitoramento:

    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);
    }

    Corrigir problemas comuns

    Esta seção cobre problemas comuns e como resolvê-los.

    Hook não dispara

    • Verifique se o nome do evento do hook está correto e sensível a maiúsculas (PreToolUse, não preToolUse)
    • Verifique se seu padrão de matcher corresponde ao nome da ferramenta exatamente
    • Certifique-se de que o hook está sob o tipo de evento correto em options.hooks
    • Para hooks SubagentStop, Stop, SessionStart, SessionEnd e Notification, matchers são ignorados. Esses hooks disparam para todos os eventos desse tipo.
    • Hooks podem não disparar quando o agente atinge o limite max_turns porque a sessão termina antes dos hooks poderem ser executados

    Matcher não filtrando conforme esperado

    Matchers apenas correspondem nomes de ferramentas, não caminhos de arquivo ou outros argumentos. Para filtrar por caminho de arquivo, verifique tool_input.file_path dentro de seu 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...
    };

    Hook timeout

    • Aumente o valor timeout na configuração HookMatcher
    • Use o AbortSignal do terceiro argumento de callback para lidar com cancelamento graciosamente em TypeScript

    Ferramenta bloqueada inesperadamente

    • Verifique todos os hooks PreToolUse para retornos permissionDecision: 'deny'
    • Adicione logging aos seus hooks para ver qual permissionDecisionReason eles estão retornando
    • Verifique se os padrões de matcher não são muito amplos (um matcher vazio corresponde a todas as ferramentas)

    Entrada modificada não aplicada

    • Certifique-se de que updatedInput está dentro de hookSpecificOutput, não no nível superior:

      return {
        hookSpecificOutput: {
          hookEventName: input.hook_event_name,
          permissionDecision: 'allow',
          updatedInput: { command: 'new command' }
        }
      };
    • Você também deve retornar permissionDecision: 'allow' para que a modificação de entrada tenha efeito

    Hooks de sessão não disponíveis

    Hooks SessionStart, SessionEnd e Notification estão disponíveis apenas no SDK TypeScript. O SDK Python não suporta esses eventos devido a limitações de configuração.

    Prompts de permissão de subagente se multiplicando

    Ao gerar múltiplos subagentes, cada um pode solicitar permissões separadamente. Subagentes não herdam automaticamente permissões de agente pai. Para evitar prompts repetidos, use hooks PreToolUse para aprovar automaticamente ferramentas específicas, ou configure regras de permissão que se apliquem a sessões de subagente.

    Loops recursivos de hook com subagentes

    Um hook UserPromptSubmit que gera subagentes pode criar loops infinitos se esses subagentes disparem o mesmo hook. Para evitar isso:

    • Verifique um indicador de subagente na entrada do hook antes de gerar
    • Use o campo parent_tool_use_id para detectar se você já está em um contexto de subagente
    • Escope hooks para executar apenas para a sessão de agente de nível superior

    systemMessage não aparecendo na saída

    O campo systemMessage adiciona contexto à conversa que o modelo vê, mas pode não aparecer em todos os modos de saída do SDK. Se você precisar exibir decisões de hook para sua aplicação, registre-as separadamente ou use um canal de saída dedicado.

    Saiba mais

    • Permissões: controlar o que seu agente pode fazer
    • Ferramentas Personalizadas: construir ferramentas para estender capacidades do agente
    • Referência do SDK TypeScript
    • Referência do SDK Python
    • Hooks disponíveis
    • Casos de uso comuns
    • Configurar hooks
    • Matchers
    • Entradas de função de callback
    • Dados de entrada
    • Saídas de callback
    • Lidar com cenários avançados
    • Encadeando múltiplos hooks
    • Matchers de ferramentas específicas com regex
    • Rastreando atividade de subagente
    • Operações assíncronas em hooks
    • Enviando notificações (apenas TypeScript)
    • Corrigir problemas comuns
    • Hook não dispara
    • Matcher não filtrando conforme esperado
    • Hook timeout
    • Ferramenta bloqueada inesperadamente
    • Entrada modificada não aplicada
    • Hooks de sessão não disponíveis
    • Prompts de permissão de subagente se multiplicando
    • Loops recursivos de hook com subagentes
    • systemMessage não aparecendo na saída
    • Saiba mais
    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())
    Injetar contexto adicional em prompts
    StopSimSimParada de execução do agenteSalvar estado da sessão antes de sair
    SubagentStartNãoSimInicialização de subagentteRastrear geração de tarefas paralelas
    SubagentStopSimSimConclusão de subagenteAgregar resultados de tarefas paralelas
    PreCompactSimSimSolicitação de compactação de conversaArquivar transcrição completa antes de resumir
    PermissionRequestNãoSimDiálogo de permissão seria exibidoManipulação de permissão personalizada
    SessionStartNãoSimInicialização de sessãoInicializar logging e telemetria
    SessionEndNãoSimEncerramento de sessãoLimpar recursos temporários
    NotificationNãoSimMensagens de status do agenteEnviar atualizações de status do agente para Slack ou PagerDuty
    -
    Obrigatório. Array de funções de callback para executar quando o padrão corresponder
    timeoutnumber60Timeout em segundos; aumente para hooks que fazem chamadas de API externas
    Mensagem de erro da falha na execução da ferramenta
    PostToolUseFailureTS
    is_interruptbooleanSe a falha foi causada por uma interrupçãoPostToolUseFailureTS
    promptstringO texto do prompt do usuárioUserPromptSubmit
    stop_hook_activebooleanSe um hook de parada está sendo processadoStop, SubagentStop
    agent_idstringIdentificador único para o subagenteSubagentStartTS, SubagentStopTS
    agent_typestringTipo/função do subagenteSubagentStartTS
    agent_transcript_pathstringCaminho para a transcrição da conversa do subagenteSubagentStopTS
    triggerstringO que disparou a compactação: manual ou autoPreCompact
    custom_instructionsstringInstruções personalizadas fornecidas para compactaçãoPreCompact
    permission_suggestionsarrayAtualizações de permissão sugeridas para a ferramentaPermissionRequestTS
    sourcestringComo a sessão começou: startup, resume, clear ou compactSessionStartTS
    reasonstringPor que a sessão terminou: clear, logout, prompt_input_exit, bypass_permissions_disabled ou otherSessionEndTS
    messagestringMensagem de status do agenteNotificationTS
    notification_typestringTipo de notificação: permission_prompt, idle_prompt, auth_success ou elicitation_dialogNotificationTS
    titlestringTítulo opcional definido pelo agenteNotificationTS
    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 {}
    Mensagem injetada na conversa para Claude ver
    object
    PreToolUse
    Entrada de ferramenta modificada (requer permissionDecision: 'allow')
    additionalContextstringPostToolUse, UserPromptSubmit, SessionStartTS, SubagentStartTSContexto adicionado à conversa
    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 {}

    Inclua hookEventName em hookSpecificOutput para identificar qual tipo de hook a saída é