For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
Navegação principal
Theme

Hooks

Execute scripts ou ferramentas MCP durante o ciclo de vida do Codex

Os hooks permitem ampliar os recursos do Codex. Com eles, você pode executar scripts ou ferramentas MCP durante o ciclo de execução com agentes de IA para, por exemplo:

  • Enviar o chat a um sistema personalizado de registro e análise de dados
  • Verificar os prompts da equipe para impedir o envio de chaves de API coladas por engano
  • Resumir chats para criar memórias persistentes automaticamente
  • Executar uma validação personalizada ao final de um turno do chat para garantir o cumprimento de padrões
  • Personalizar os prompts ao trabalhar em um diretório específico

Como os hooks são executados:

  • Todos os hooks que correspondem ao evento são executados, mesmo que venham de arquivos diferentes.
  • Quando vários hooks de comando correspondem ao mesmo evento, eles são iniciados em paralelo. Assim, um hook não pode impedir que outro seja iniciado.
  • Antes da execução, é preciso revisar os hooks não gerenciados e marcá-los como confiáveis.

Os hooks são executados em diferentes momentos da conversa:

Momento Hooks
Durante um turno PreToolUse, PermissionRequest, PostToolUse, PreCompact, PostCompact, UserPromptSubmit, SubagentStop, Stop
A cada tentativa de solicitação ao modelo PreModelRequest, PostModelRequest
Quando você interrompe um turno ativo Interrupt (não é executado para subagentes)
Quando uma sessão ou um subagente é iniciado SessionStart, SubagentStart
Quando a thread principal termina SessionEnd (não é executado para subagentes)

Onde o Codex procura hooks

O Codex procura hooks junto às camadas de configuração ativas, em um destes formatos:

  • hooks.json
  • Tabelas [hooks] diretamente no config.toml

Os plugins instalados também podem incluir configurações de ciclo de vida no manifesto do plugin ou no arquivo padrão hooks/hooks.json. Consulte Criar plugins para conhecer as regras de empacotamento.

Na prática, os quatro locais mais úteis são:

  • ~/.codex/hooks.json
  • ~/.codex/config.toml
  • <repo>/.codex/hooks.json
  • <repo>/.codex/config.toml

Se houver mais de uma origem de hooks, o Codex carrega todos os hooks correspondentes. As camadas de configuração de maior precedência não substituem os hooks das camadas de menor precedência. Se uma camada contiver tanto um arquivo hooks.json quanto tabelas [hooks] na própria configuração, o Codex combina os dois e exibe um aviso na inicialização. Prefira um único formato por camada.

O Codex também pode encontrar hooks incluídos nos plugins habilitados. Ele carrega esses hooks junto com os de outras origens e aplica o mesmo processo de revisão de confiança usado para os demais hooks não gerenciados.

O Codex só carrega os hooks locais de um projeto quando a camada .codex/ do projeto é confiável. Em projetos não confiáveis, o Codex ainda carrega os hooks do usuário e do sistema a partir das respectivas camadas de configuração ativas.

Revisar hooks e marcá-los como confiáveis

O Codex lista os hooks configurados antes de determinar quais podem ser executados. Para que um hook não gerenciado possa ser executado, você precisa revisar sua definição exata e marcá-la como confiável. O Codex associa essa decisão ao hash atual do hook. Assim, ele sinaliza hooks novos ou alterados para revisão e ignora esses hooks até que você os marque como confiáveis.

Use /hooks na CLI para inspecionar as origens dos hooks, revisar hooks novos ou alterados, marcar hooks como confiáveis ou desabilitar hooks não gerenciados individualmente. Se houver hooks pendentes de revisão na inicialização, o Codex exibe um aviso orientando você a abrir /hooks.

Os hooks gerenciados provenientes do sistema, do MDM, da nuvem ou de requirements.toml são identificados como gerenciados e considerados confiáveis por política. O usuário não pode desabilitá-los na interface de consulta de hooks.

Para uma automação pontual que já verifica as origens dos hooks fora do Codex, passe --dangerously-bypass-hook-trust para executar os hooks habilitados sem exigir um registro persistente de confiança nessa invocação.

Estrutura da configuração

Os hooks são organizados em três níveis:

  • Um evento de hook, como PreToolUse, PostToolUse, PreCompact, SubagentStart ou Stop
  • Um grupo de correspondência que define os critérios para selecionar ocorrências desse evento
  • Um ou mais manipuladores de hook que são executados quando os critérios do grupo são atendidos
{
  "description": "Optional lifecycle hooks for this workspace.",
  "hooks": {
    "SessionStart": [
      {
        "matcher": "startup|resume",
        "hooks": [
          {
            "type": "command",
            "command": "python3 ~/.codex/hooks/session_start.py",
            "statusMessage": "Loading session notes",
            "additionalContextLimit": 5000
          }
        ]
      }
    ],
    "SessionEnd": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "python3 ~/.codex/hooks/session_end.py",
            "timeout": 3
          }
        ]
      }
    ],
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/pre_tool_use_policy.py\"",
            "statusMessage": "Checking Bash command"
          }
        ]
      }
    ],
    "PermissionRequest": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/permission_request.py\"",
            "statusMessage": "Checking approval request"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/post_tool_use_review.py\"",
            "statusMessage": "Reviewing Bash output"
          }
        ]
      }
    ],
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/user_prompt_submit_data_flywheel.py\""
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/stop_continue.py\"",
            "timeout": 30
          }
        ]
      }
    ]
  }
}

Observações:

  • description é um metadado opcional no nível superior de um arquivo hooks.json. Ele não altera quais hooks são executados.
  • timeout é expresso em segundos.
  • Se você omitir timeout, o Codex usará 600 segundos para a maioria dos hooks.
    • SessionEnd e Interrupt usam 1 segundo por padrão e aceitam até 3 segundos.
  • statusMessage é opcional.
  • additionalContextLimit define quanto additionalContext um hook de comando pode enviar ao modelo antes que o Codex passe a salvar o texto completo em disco e enviar uma prévia mais curta. Consulte Saídas extensas de hooks.
  • commandWindows é uma substituição opcional do comando, exclusiva do Windows. Em TOML, use command_windows ou commandWindows.
  • Defina async como true para executar um hook de comando em segundo plano.
  • Há suporte para manipuladores command e mcp_tool. O Codex interpreta os manipuladores prompt e agent, mas não os executa.
  • Os comandos usam o cwd da sessão como diretório de trabalho.
  • Para hooks locais do repositório, prefira resolver o caminho a partir da raiz do Git em vez de usar um caminho relativo como .codex/hooks/.... O Codex pode ser iniciado em um subdiretório. Usar a raiz do Git mantém estável o caminho do hook.

Configuração TOML equivalente diretamente no config.toml:

[[hooks.SessionStart]]
matcher = "^compact$"

[[hooks.SessionStart.hooks]]
type = "command"
command = '/usr/bin/python3 "$(git rev-parse --show-toplevel)/.codex/hooks/session_start.py"'
additionalContextLimit = 5000

[[hooks.PreToolUse]]
matcher = "^Bash$"

[[hooks.PreToolUse.hooks]]
type = "command"
command = '/usr/bin/python3 "$(git rev-parse --show-toplevel)/.codex/hooks/pre_tool_use_policy.py"'
timeout = 30
statusMessage = "Checking Bash command"

[[hooks.PostToolUse]]
matcher = "^Bash$"

[[hooks.PostToolUse.hooks]]
type = "command"
command = '/usr/bin/python3 "$(git rev-parse --show-toplevel)/.codex/hooks/post_tool_use_review.py"'
timeout = 30
statusMessage = "Reviewing Bash output"

Hooks de ferramentas MCP

Um hook de ferramenta MCP permite que um evento do ciclo de vida chame uma ferramenta em um servidor MCP já conectado. Ele envia argumentos estruturados diretamente à ferramenta e segue o mesmo processo de revisão de confiança e o mesmo contrato de saída de um hook de comando.

Configurar um hook de ferramenta MCP

Este hook solicita ao servidor MCP scanner que analise cada patch depois que o Codex grava ou edita arquivos:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "mcp_tool",
            "server": "scanner",
            "tool": "scan_patch",
            "input": { "patch": "${tool_input.command}" },
            "timeout": 30,
            "statusMessage": "Scanning edited files"
          }
        ]
      }
    ]
  }
}
Campo Significado
type Deve ser mcp_tool.
server Nome obrigatório de um servidor MCP já conectado.
tool Nome obrigatório de uma ferramenta disponibilizada por esse servidor.
input Objeto JSON opcional com modelos de argumentos. O padrão é {}.
timeout Tempo limite opcional de execução ativa, em segundos. O padrão é 600.
statusMessage Mensagem opcional exibida durante a execução do hook.

Expandir argumentos a partir do evento do hook

Use ${field.nested} para ler um campo do evento do hook usando a notação de ponto. Quando um marcador ocupa todo o valor, ele preserva o tipo JSON do campo. Quando faz parte de uma string maior, o valor é convertido em texto. O Codex expande objetos e arrays recursivamente.

Para um evento que contém {"tool_input":{"file_path":"src/main.rs","count":3}}, este modelo de argumentos:

{
  "path": "${tool_input.file_path}",
  "count": "${tool_input.count}",
  "message": "Scanning ${tool_input.file_path}"
}

produz o seguinte resultado:

{
  "path": "src/main.rs",
  "count": 3,
  "message": "Scanning src/main.rs"
}

Execução e ciclo de vida

  • Os hooks usam uma conexão MCP existente. Eles não iniciam nem reconectam servidores.
  • Um hook pode bloquear uma operação quando a ferramenta retorna uma decisão de bloqueio. Erros, servidores ausentes e ferramentas indisponíveis não bloqueiam a operação.
  • Os hooks de ferramentas MCP são executados de forma síncrona. Eles não solicitam aprovação para usar ferramentas nem acionam outros hooks.
  • Vale o menor tempo limite entre o do hook e o do servidor. O tempo de espera por uma resposta de elicitação MCP não entra nessa contagem.
  • Hooks SessionStart podem ser executados antes que um servidor MCP esteja pronto. Nesse caso, eles não bloqueiam a sessão.
  • SessionEnd não oferece suporte a hooks de ferramentas MCP.

Desabilitar hooks

Os hooks vêm habilitados por padrão. Para desabilitá-los no config.toml, use esta configuração:

[features]
hooks = false

Use hooks como chave do recurso. codex_hooks ainda funciona como alias obsoleto. Da mesma forma, administradores podem impor a desativação dos hooks em requirements.toml com [features].hooks = false.

Hooks gerenciados em requirements.toml

Escolha os hooks de acordo com o ambiente que coordena a tarefa.

Hooks com orquestração na nuvem

Em espaços de trabalho com a política gerenciada e os hooks remotos habilitados, o modo Work na nuvem com acesso ao computador local e os dots podem chamar um serviço MCP quando ocorrem eventos de tarefa ou de ferramenta compatíveis. Essas chamadas usam os manipuladores mcp_tool que o administrador do espaço de trabalho configura em Segurança do agente. O modo Work na nuvem sem acesso ao computador local e as contas pessoais não usam esses hooks corporativos.

A orquestração na nuvem aceita apenas hooks MCP globais, mesmo quando uma ferramenta é executada em um computador conectado. Ela não oferece suporte a manipuladores de comando, de prompt ou de agente, a hooks de configurações locais, plugins ou diretórios locais, a hooks restritos a um ambiente nem a hooks MCP de SessionEnd. Quando tanto a orquestração quanto a execução são locais, as threads exclusivamente locais do modo Work e do Codex continuam aceitando os hooks existentes.

Um hook compatível pode bloquear uma ação ao retornar uma decisão explícita de negação. Se ocorrer um erro ou o tempo limite for excedido em PreToolUse, ou se a resposta estiver malformada, a ferramenta poderá ser executada. Os hooks MCP fornecem apenas parte da trilha de auditoria. Para verificar a implantação e a cobertura da auditoria, consulte Verificar a compatibilidade dos hooks e da rede.

Hooks gerenciados no Codex local

Defina os hooks locais do Codex na seção [hooks] de requirements.toml. Para impor hooks gerenciados mesmo aos usuários que os desabilitaram localmente, fixe [features].hooks = true em requirements.toml junto com [hooks]. Para ignorar os hooks de usuários, projetos, sessões e plugins e continuar permitindo os hooks gerenciados pelo administrador, defina allow_managed_hooks_only = true.

allow_managed_hooks_only = true

[features]
hooks = true

[hooks]
managed_dir = "/enterprise/hooks"
windows_managed_dir = 'C:\enterprise\hooks'

[[hooks.PreToolUse]]
matcher = "^Bash$"

[[hooks.PreToolUse.hooks]]
type = "command"
command = "python3 /enterprise/hooks/pre_tool_use_policy.py"
command_windows = 'py -3 C:\enterprise\hooks\pre_tool_use_policy.py'
timeout = 30
statusMessage = "Checking managed Bash command"

Observações sobre hooks gerenciados:

  • managed_dir é usado no macOS e no Linux.
  • windows_managed_dir é usado no Windows.
  • O Codex não distribui os scripts de managed_dir. As ferramentas da empresa devem instalá-los e atualizá-los separadamente.
  • Os comandos dos hooks gerenciados devem usar caminhos absolutos para scripts dentro do diretório gerenciado configurado.
  • allow_managed_hooks_only = true ignora os hooks de usuários, projetos, sessões e plugins, mas ainda carrega os hooks gerenciados de requirements.toml e de outras camadas de configuração gerenciadas.

Hooks incluídos em plugins

Quando um plugin está habilitado, o Codex pode carregar seus hooks de ciclo de vida junto com os hooks do usuário, os do projeto e os gerenciados.

Por padrão, o Codex procura hooks/hooks.json na raiz do plugin. O manifesto do plugin pode substituir esse padrão com uma entrada hooks em .codex-plugin/plugin.json. A entrada pode ser um caminho com o prefixo ./, um array de caminhos com o prefixo ./, um objeto de hooks definido diretamente no manifesto ou um array desses objetos.

{
  "name": "repo-policy",
  "hooks": "./hooks/hooks.json"
}

Os caminhos dos hooks no manifesto são resolvidos a partir da raiz do plugin e devem permanecer dentro dela. Se o manifesto definir hooks, o Codex usará essas entradas em vez do arquivo padrão hooks/hooks.json.

Os comandos dos hooks de plugins recebem estas variáveis de ambiente:

  • PLUGIN_ROOT é uma extensão específica do Codex que aponta para a raiz do plugin instalado.
  • PLUGIN_DATA é uma extensão específica do Codex que aponta para o diretório de dados do plugin com permissão de gravação.
  • O Codex também define CLAUDE_PLUGIN_ROOT e CLAUDE_PLUGIN_DATA para manter a compatibilidade com hooks de plugins existentes.

Os hooks de plugins usam o mesmo schema de eventos que os demais hooks. Revise-os e marque-os como confiáveis antes da execução. Na CLI, abra /hooks. No aplicativo para desktop, selecione Revisar hooks no editor ou abra Configurações > Hooks. Se uma atualização do plugin alterar um dos scripts incluídos, o Codex exigirá uma nova revisão, mesmo que a definição do hook continue igual.

Padrões de correspondência

O campo matcher contém uma expressão regular em formato de string que filtra as ocorrências que acionam os hooks. Use "*", "" ou omita matcher para selecionar todas as ocorrências de um evento compatível.

Atualmente, apenas alguns eventos do Codex levam matcher em conta:

Evento O que matcher filtra Observações
PermissionRequest nome da ferramenta Há suporte para Bash, apply_patch* e nomes de ferramentas MCP
PostToolUse nome da ferramenta Consulte Ferramentas abrangidas
PostCompact gatilho da compactação Os valores são manual ou auto
PreModelRequest, PostModelRequest sem suporte Ambos os eventos ocorrem a cada tentativa de solicitação ao modelo
PreCompact gatilho da compactação Os valores são manual ou auto
PreToolUse nome da ferramenta Consulte Ferramentas abrangidas
SessionEnd motivo do encerramento Atualmente, apenas other
SessionStart origem da sessão Os valores são startup, resume, clear, compact e fork
SubagentStart tipo de subagente Os valores dependem do subagente que inicia a execução
SubagentStop tipo de subagente Os valores dependem do subagente que encerra a execução
UserPromptSubmit sem suporte O evento ignora qualquer matcher configurado
Stop sem suporte O evento ignora qualquer matcher configurado
Interrupt sem suporte O evento ignora qualquer matcher configurado

*Para apply_patch, os valores de matcher também podem ser Edit ou Write.

Exemplos:

  • Bash
  • ^apply_patch$
  • Edit|Write
  • mcp__filesystem__read_file
  • mcp__filesystem__.*
  • startup|resume|clear|compact|fork
  • manual|auto

Ferramentas abrangidas

PreToolUse e PostToolUse podem observar chamadas além das de shell e MCP. A maioria das ferramentas de função locais usa o mesmo mecanismo de hooks. Assim, você pode selecionar essas ferramentas pelo nome, inspecionar seus argumentos JSON e, no caso de PreToolUse, bloquear ou reescrever a chamada.

Mecanismo de execução PreToolUse PostToolUse Observações
Comandos de shell Sim Sim Use Bash para selecionar esses comandos.
Execução unificada (exec_command) Sim Sim Use Bash. Uma consulta posterior com write_stdin pode entregar o PostToolUse do comando original quando ele terminar.
apply_patch Sim Sim Use apply_patch, Edit ou Write.
Ferramentas MCP Sim Sim Use o nome da ferramenta MCP, como mcp__filesystem__read_file.
Outras ferramentas de função locais Sim Sim Use o nome da ferramenta de função, como update_plan. A ferramenta spawn_agent também corresponde a Agent.
Ferramentas hospedadas, como WebSearch Não Não Essas ferramentas não usam o mecanismo de hooks das ferramentas de função locais.

write_stdin serve como transporte para uma sessão de execução unificada existente. Ele não executa PreToolUse novamente ao enviar dados de entrada ou consultar um comando que já passou por PreToolUse.

Alguns mecanismos especializados de execução de ferramentas podem dispensar o mecanismo padrão de hooks. Os hooks de ferramentas oferecem uma proteção adicional, mas não garantem, por si só, a aplicação de todas as políticas.

Campos de entrada comuns

Cada hook de comando recebe um objeto JSON em stdin.

Estes são os campos compartilhados que você normalmente usará:

Campo Tipo Significado
session_id string ID da sessão atual do Codex. Os hooks de subagentes usam o ID da sessão pai.
transcript_path string | null Caminho do arquivo de transcrição da sessão, se houver
cwd string Diretório de trabalho da sessão
hook_event_name string Nome do evento de hook atual
model string Extensão específica do Codex. Slug do modelo ativo

Os hooks cujo escopo é um turno incluem turn_id como extensão específica do Codex nas tabelas dos respectivos eventos.

SessionStart, PreToolUse, PermissionRequest, PostToolUse, UserPromptSubmit, SubagentStart, SubagentStop, Stop e Interrupt também incluem permission_mode, que indica o modo de permissão atual: default, acceptEdits, plan, dontAsk ou bypassPermissions.

transcript_path facilita o acesso à transcrição do chat. O formato da transcrição não é uma interface estável para hooks e pode mudar com o tempo.

Se precisar do formato completo dos dados transmitidos, consulte Schemas.

Campos de saída comuns

SessionStart, PreCompact, PostCompact, UserPromptSubmit, SubagentStop e Stop aceitam os campos JSON compartilhados a seguir. SubagentStart aceita a mesma estrutura para systemMessage e para o contexto específico do hook, mas continue: false não interrompe o subagente:

{
  "continue": true,
  "stopReason": "optional",
  "systemMessage": "optional",
  "suppressOutput": false
}
Campo Efeito
continue Se for false, marca essa execução do hook como interrompida
stopReason Registra o motivo da interrupção
systemMessage Exibe um aviso na interface ou no fluxo de eventos
suppressOutput O Codex interpreta o campo, mas o recurso ainda não foi implementado

O Codex considera o código de saída 0 sem dados de saída uma execução bem-sucedida e continua.

PreToolUse e PermissionRequest aceitam systemMessage, mas ainda não oferecem suporte a continue, stopReason nem suppressOutput. Se um hook PreToolUse retornar um desses campos sem suporte, o Codex registra a execução do hook como falha, informa o erro e prossegue com a chamada da ferramenta.

PostToolUse aceita systemMessage, continue: false e stopReason. O Codex interpreta suppressOutput, mas ainda não oferece suporte a esse campo nesse evento.

Saídas extensas de hooks

Por padrão, o Codex limita cada mensagem de saída de hook visível ao modelo a cerca de 2.500 tokens. Se um hook retornar mais, o Codex salvará o texto completo em <temp_dir>/hook_outputs/<session_id>/<uuid>.txt e enviará ao modelo uma prévia com o início e o fim do texto e o caminho do arquivo salvo. Esse comportamento é chamado de descarregamento em disco: o Codex armazena em disco a saída que excede o limite e a substitui por uma prévia mais curta, visível ao modelo. Se não for possível gravar o arquivo, o modelo ainda receberá uma prévia truncada.

Mantenha conciso o contexto fornecido por hooks e plugins. O contexto de vários hooks e plugins se acumula e pode prejudicar o desempenho do modelo. Aumentar additionalContextLimit aumenta esse risco. Evite definir o limite como 0, a menos que o próprio hook imponha um limite rígido à saída. Caso contrário, um único hook pode consumir toda a janela de contexto.

Para qualquer hook de comando que retorne additionalContext, defina additionalContextLimit no manipulador para ajustar o limite aproximado de tokens:

{
  "type": "command",
  "command": "python3 ~/.codex/hooks/session_start.py",
  "additionalContextLimit": 5000
}

Omita additionalContextLimit para usar o limite padrão de 2500 tokens. Use um inteiro positivo para escolher outro limite ou 0 para enviar todo o contexto adicional do manipulador diretamente ao modelo. O Codex avalia cada manipulador correspondente de forma independente. Nos eventos que não podem produzir contexto adicional, o Codex ignora additionalContextLimit e exibe um aviso de configuração.

A configuração se aplica apenas a additionalContext. O feedback das ferramentas e os prompts de continuação mantêm o limite padrão.

Como as saídas que excedem o limite podem ser gravadas em disco, evite retornar segredos ou outros dados confidenciais na saída dos hooks.

Executar hooks em segundo plano

Por padrão, o Codex espera um hook de comando terminar antes de continuar a operação que o acionou. Defina async como true para executar um hook de comando em segundo plano enquanto o Codex prossegue.

Configurar um hook em segundo plano

Adicione "async": true a um manipulador de comando em hooks.json:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python3 ~/.codex/hooks/post_tool_use.py",
            "async": true,
            "timeout": 120
          }
        ]
      }
    ]
  }
}

Para um hook definido diretamente no config.toml, use async = true:

[[hooks.PostToolUse]]
matcher = "Bash"

[[hooks.PostToolUse.hooks]]
type = "command"
command = "python3 ~/.codex/hooks/post_tool_use.py"
async = true
timeout = 120

Os hooks em segundo plano usam a mesma entrada, os mesmos critérios de correspondência, a mesma revisão de confiança, o mesmo tempo limite e o mesmo tratamento de saídas extensas que os hooks de comando síncronos. Como nos demais hooks de comando, timeout é expresso em segundos e tem 600 como valor padrão. Os hooks Interrupt têm um tempo limite padrão de um segundo e máximo de três segundos, inclusive quando executados em segundo plano.

Como os hooks são executados em segundo plano

Quando um hook em segundo plano termina, o Codex entrega as informações de saída compatíveis no próximo momento seguro da conversa:

  • Se houver um turno ativo, o Codex espera a solicitação atual ao modelo e as chamadas de ferramentas terminarem. Em seguida, disponibiliza a saída para a próxima solicitação ao modelo nesse turno.
  • Se não houver turno ativo, o Codex espera até o próximo turno do usuário. A conclusão de um hook em segundo plano não inicia um novo turno.

Use a mesma saída JSON específica do evento que usaria em um hook síncrono. O Codex adiciona additionalContext ao contexto do modelo e exibe systemMessage como aviso.

Hooks em segundo plano não podem bloquear, aprovar, reescrever nem controlar de outra forma a operação que os acionou. Use hooks síncronos para aplicar políticas de ferramentas, tomar decisões de permissão, rejeitar prompts ou dar continuidade a um turno.

Limitações

  • O Codex executa até oito hooks em segundo plano simultaneamente por sessão. Os demais aguardam até que um dos hooks em execução termine.
  • Cada invocação correspondente é executada de forma independente. Os hooks em segundo plano podem terminar em uma ordem diferente daquela em que foram iniciados.
  • Quando a sessão termina, o Codex cancela os hooks em segundo plano que ainda não terminaram e descarta as saídas que ainda não entregou.
  • Os hooks SessionEnd sempre são executados de forma síncrona.

Hooks

SessionStart

Neste evento, matcher filtra o campo source.

Campos além dos campos de entrada comuns:

Campo Tipo Significado
source string Como a sessão começou: startup, resume, clear, compact ou fork

Uma thread criada por fork usa source: "fork". Ao retomar uma thread com um histórico fornecido, o Codex continua usando source: "resume".

O texto simples enviado a stdout é adicionado como contexto extra de desenvolvedor.

O JSON enviado a stdout aceita os campos de saída comuns e esta estrutura específica do hook:

{
  "hookSpecificOutput": {
    "hookEventName": "SessionStart",
    "additionalContext": "Load the workspace conventions before editing."
  }
}

O texto de additionalContext é adicionado como contexto extra de desenvolvedor.

Depois que o Codex compacta uma sessão raiz, os hooks SessionStart que correspondem a source: "compact" são executados antes da próxima solicitação ao modelo. Isso também vale quando a compactação automática ocorre no meio de um turno. O Codex entrega o contexto adicional do hook assim que retoma a execução, sem esperar por um turno posterior do usuário. Se o hook retornar continue: false, o Codex encerra o turno sem enviar outra solicitação ao modelo.

SessionEnd

SessionEnd permite executar um comando quando uma sessão termina, por exemplo, para salvar anotações finais ou limpar arquivos. Ele é executado na thread principal quando você arquiva ou exclui uma conversa ainda aberta, quando o Codex é encerrado normalmente ou quando uma conversa permanece inativa e sem estar aberta em nenhum cliente conectado por 30 minutos. Ele não é executado para subagentes.

Sair da visualização de uma conversa ou chamar thread/unsubscribe não encerra a sessão de imediato e, portanto, não aciona SessionEnd imediatamente. Seu hook ainda pode ler a transcrição da sessão durante a execução.

Neste evento, matcher filtra reason. Por enquanto, reason é sempre other. Você pode omitir matcher ou usar other para executar o hook em todas as ocorrências de SessionEnd.

Campos além dos campos de entrada comuns:

Campo Tipo Significado
reason string Motivo do encerramento da sessão: other

Por exemplo, um comando SessionEnd recebe:

{
  "session_id": "thr_123",
  "transcript_path": "/workspace/.codex/rollout.jsonl",
  "cwd": "/workspace",
  "hook_event_name": "SessionEnd",
  "reason": "other"
}

Os hooks SessionEnd sempre são executados de forma síncrona, mesmo quando async é true. Sua saída é apenas informativa e não influencia o comportamento do Codex nem mantém a thread aberta. Se um comando exceder o tempo limite ou terminar com erro, o Codex informará uma falha no hook.

SubagentStart

Neste evento, matcher filtra o campo agent_type.

Campos além dos campos de entrada comuns:

Campo Tipo Significado
turn_id string Extensão específica do Codex. ID do turno ativo do Codex
agent_id string Identificador do subagente
agent_type string Tipo ou perfil do subagente
permission_mode string Modo de permissão atual

O texto simples enviado a stdout é adicionado como contexto extra de desenvolvedor para o subagente.

O JSON enviado a stdout aceita systemMessage e esta estrutura específica do hook:

{
  "hookSpecificOutput": {
    "hookEventName": "SubagentStart",
    "additionalContext": "Review the repository test conventions first."
  }
}

O texto de additionalContext é adicionado como contexto extra de desenvolvedor para o subagente. O Codex interpreta continue: false por compatibilidade, mas isso não impede a inicialização do subagente.

PreToolUse

PreToolUse pode interceptar comandos Bash, edições de arquivos feitas com apply_patch, chamadas de ferramentas MCP e chamadas de outras ferramentas de função locais. Consulte Ferramentas abrangidas para conhecer os mecanismos compatíveis e as exceções.

O campo matcher filtra tool_name e os aliases de correspondência. Para edições de arquivos com apply_patch, os valores de matcher podem ser apply_patch, Edit ou Write. A entrada do hook continua indicando tool_name: "apply_patch".

Campos além dos campos de entrada comuns:

Campo Tipo Significado
turn_id string Extensão específica do Codex. ID do turno ativo do Codex
tool_name string Nome canônico da ferramenta para o hook, como Bash, apply_patch ou um nome MCP como mcp__fs__read
tool_use_id string ID da chamada da ferramenta nesta invocação
tool_input JSON value Entrada específica da ferramenta. Bash e apply_patch usam tool_input.command. As ferramentas MCP e as demais ferramentas de função locais enviam seus argumentos.

O Codex ignora texto simples em stdout.

O JSON enviado a stdout pode usar systemMessage. Para negar uma chamada de ferramenta compatível, retorne esta estrutura específica do hook:

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "Destructive command blocked by hook."
  }
}

O Codex também aceita este formato anterior de bloqueio:

{
  "decision": "block",
  "reason": "Destructive command blocked by hook."
}

Você também pode usar o código de saída 2 e escrever o motivo do bloqueio em stderr.

Para adicionar contexto visível ao modelo sem bloquear a chamada, retorne hookSpecificOutput.additionalContext:

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "additionalContext": "The pending command touches generated files."
  }
}

Para reescrever uma chamada de ferramenta compatível sem bloqueá-la, retorne permissionDecision: "allow" com updatedInput:

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow",
    "updatedInput": {
      "command": "echo rewritten"
    }
  }
}

Para comandos Bash e apply_patch, updatedInput deve incluir um campo command do tipo string. Para ferramentas MCP e outras ferramentas de função locais, updatedInput é o objeto que substitui os argumentos originais. Retorne updatedInput apenas com permissionDecision: "allow". O Codex informa um erro para outros formatos de updatedInput.

O Codex interpreta permissionDecision: "ask", o formato legado decision: "approve", continue: false, stopReason e suppressOutput, mas ainda não oferece suporte a eles. Nesses casos, registra a execução do hook como falha, informa o erro e prossegue com a chamada da ferramenta.

PermissionRequest

PermissionRequest é executado quando o Codex está prestes a pedir aprovação, por exemplo, para elevar privilégios no shell ou autorizar acesso à rede gerenciada. O hook pode aprovar ou negar a solicitação, ou deixar a decisão em aberto para que o pedido de aprovação seja exibido normalmente. Ele não é executado para comandos que dispensam aprovação.

O campo matcher filtra tool_name e os aliases de correspondência. Os valores canônicos atuais incluem Bash, apply_patch e nomes de ferramentas MCP como mcp__server__tool. A ferramenta apply_patch também corresponde a Edit e Write.

Campos além dos campos de entrada comuns:

Campo Tipo Significado
turn_id string Extensão específica do Codex. ID do turno ativo do Codex
tool_name string Nome canônico da ferramenta para o hook, como Bash, apply_patch ou um nome MCP como mcp__fs__read
tool_input JSON value Entrada específica da ferramenta. Bash e apply_patch usam tool_input.command, enquanto as ferramentas MCP enviam todos os argumentos.
tool_input.description string | null Descrição legível do motivo do pedido de aprovação, quando disponível no Codex

O Codex ignora texto simples em stdout.

Algumas entradas de ferramentas podem incluir uma descrição legível, mas não conte com a presença do campo tool_input.description em todas as ferramentas.

Para aprovar a solicitação, retorne:

{
  "hookSpecificOutput": {
    "hookEventName": "PermissionRequest",
    "decision": {
      "behavior": "allow"
    }
  }
}

Para negar a solicitação, retorne:

{
  "hookSpecificOutput": {
    "hookEventName": "PermissionRequest",
    "decision": {
      "behavior": "deny",
      "message": "Blocked by repository policy."
    }
  }
}

Se vários hooks correspondentes retornarem decisões, qualquer deny terá precedência. Caso contrário, um allow permite que a solicitação prossiga sem exibir o pedido de aprovação. Se nenhum hook correspondente tomar uma decisão, o Codex seguirá o fluxo normal de aprovação.

Não retorne updatedInput, updatedPermissions nem interrupt para PermissionRequest. Esses campos estão reservados para uso futuro e, atualmente, retorná-los bloqueia a solicitação por segurança.

PostToolUse

PostToolUse é executado depois que ferramentas compatíveis produzem uma saída, incluindo Bash, apply_patch, chamadas de ferramentas MCP e outras ferramentas de função locais. No caso do Bash, também é executado após comandos que terminam com um código de saída diferente de zero. Ele não pode desfazer os efeitos de uma ferramenta que já foi executada. Consulte Ferramentas abrangidas para conhecer os mecanismos compatíveis e as exceções.

O campo matcher filtra tool_name e os aliases de correspondência. Para edições de arquivos com apply_patch, os valores de matcher podem ser apply_patch, Edit ou Write. A entrada do hook continua indicando tool_name: "apply_patch".

Campos além dos campos de entrada comuns:

Campo Tipo Significado
turn_id string Extensão específica do Codex. ID do turno ativo do Codex
tool_name string Nome canônico da ferramenta para o hook, como Bash, apply_patch ou um nome MCP como mcp__fs__read
tool_use_id string ID da chamada da ferramenta nesta invocação
tool_input JSON value Entrada específica da ferramenta. Bash e apply_patch usam tool_input.command. As ferramentas MCP e as demais ferramentas de função locais enviam seus argumentos.
tool_response JSON value Saída específica da ferramenta. As ferramentas MCP enviam o resultado da chamada MCP. As demais ferramentas de função locais normalmente enviam a saída destinada ao modelo.

O Codex ignora texto simples em stdout.

O JSON enviado a stdout pode usar systemMessage e esta estrutura específica do hook:

{
  "decision": "block",
  "reason": "The Bash output needs review before continuing.",
  "hookSpecificOutput": {
    "hookEventName": "PostToolUse",
    "additionalContext": "The command updated generated files."
  }
}

O texto de additionalContext é adicionado como contexto extra de desenvolvedor.

Neste evento, decision: "block" não desfaz o comando Bash já concluído. O Codex registra o feedback, substitui o resultado da ferramenta por esse feedback e retoma a execução do modelo a partir da mensagem fornecida pelo hook.

Você também pode usar o código de saída 2 e escrever o motivo do feedback em stderr.

Para interromper o processamento normal do resultado original da ferramenta após a execução do comando, retorne continue: false. O Codex substituirá o resultado da ferramenta pelo seu feedback ou pelo texto de interrupção e continuará a partir daí.

O Codex interpreta updatedMCPToolOutput e suppressOutput, mas ainda não oferece suporte a eles. Nesses casos, registra a execução do hook como falha, informa o erro e continua processando normalmente o resultado da ferramenta.

Chamadas de ferramentas no modo de código

Quando um modelo usa o modo de código para chamar uma ferramenta a partir de JavaScript, as decisões dos hooks se aplicam a essa chamada aninhada. PreToolUse pode impedir a execução da ferramenta ou reescrever sua entrada. Um bloqueio de PostToolUse não pode desfazer os efeitos da ferramenta, mas pode impedir que o script em execução receba o resultado original.

Resultado do hook Comportamento no modo de código
PreToolUse bloqueia a chamada A promessa da ferramenta é rejeitada antes da execução da ferramenta.
PreToolUse retorna updatedInput A ferramenta é executada com a entrada reescrita, e a promessa é resolvida com o resultado.
PostToolUse retorna decision: "block" ou termina com o código 2 A ferramenta é executada. Em seguida, a promessa é rejeitada com o motivo fornecido pelo hook.
PostToolUse retorna continue: false O Codex usa o feedback do hook como resultado visível ao modelo, mas não rejeita a promessa da chamada aninhada.

PreModelRequest e PostModelRequest

Use esses hooks para registrar as solicitações ao modelo, inclusive as novas tentativas dentro do mesmo turno. PreModelRequest é executado antes de cada tentativa. PostModelRequest informa o resultado. Ambos recebem o modelo e turn_id, além de agent_id e agent_type quando disponíveis. A saída desses hooks serve apenas para diagnóstico. Ela não pode alterar o contexto do modelo nem bloquear uma solicitação.

PostModelRequest inclui três campos adicionais:

Campo Significado
status completed, failed ou cancelled.
error Mensagem de erro, se disponível. Caso contrário, null.
token_usage Contagens de tokens da tentativa, se disponíveis. Caso contrário, null.

PreCompact

PreCompact é executado antes de o Codex compactar o chat. O campo matcher filtra trigger, cujos valores são manual e auto.

Campos além dos campos de entrada comuns:

Campo Tipo Significado
turn_id string Extensão específica do Codex. ID do turno ativo do Codex
trigger string O que acionou a compactação: manual ou auto

O Codex ignora texto simples em stdout.

O JSON enviado a stdout aceita os campos de saída comuns. Se um hook PreCompact correspondente retornar continue: false, o Codex interromperá a execução antes da compactação.

PostCompact

PostCompact é executado depois que o Codex compacta o chat. O campo matcher filtra trigger, cujos valores são manual e auto.

Campos além dos campos de entrada comuns:

Campo Tipo Significado
turn_id string Extensão específica do Codex. ID do turno ativo do Codex
trigger string O que acionou a compactação: manual ou auto

O Codex ignora texto simples em stdout.

O JSON enviado a stdout aceita os campos de saída comuns. Se um hook PostCompact correspondente retornar continue: false, o Codex interromperá a execução após a compactação.

UserPromptSubmit

Atualmente, este evento não usa matcher.

Campos além dos campos de entrada comuns:

Campo Tipo Significado
turn_id string Extensão específica do Codex. ID do turno ativo do Codex
prompt string Prompt do usuário que está prestes a ser enviado

O texto simples enviado a stdout é adicionado como contexto extra de desenvolvedor.

O JSON enviado a stdout aceita os campos de saída comuns e esta estrutura específica do hook:

{
  "hookSpecificOutput": {
    "hookEventName": "UserPromptSubmit",
    "additionalContext": "Ask for a clearer reproduction before editing files."
  }
}

O texto de additionalContext é adicionado como contexto extra de desenvolvedor.

Para bloquear o prompt, retorne:

{
  "decision": "block",
  "reason": "Ask for confirmation before doing that."
}

Você também pode usar o código de saída 2 e escrever o motivo do bloqueio em stderr.

SubagentStop

Neste evento, matcher filtra o campo agent_type.

Campos além dos campos de entrada comuns:

Campo Tipo Significado
turn_id string Extensão específica do Codex. ID do turno ativo do Codex
agent_id string Identificador do subagente
agent_type string Tipo ou perfil do subagente
agent_transcript_path string | null Caminho do arquivo de transcrição do subagente, se houver
stop_hook_active boolean Indica se o subagente já recebeu uma instrução para continuar
last_assistant_message string | null Mensagem mais recente do assistente do subagente, se disponível

SubagentStop espera JSON em stdout quando termina com o código 0. Uma saída em texto simples é inválida para este evento.

O JSON enviado a stdout aceita os campos de saída comuns. Para pedir ao Codex que dê continuidade à execução do subagente, retorne:

{
  "decision": "block",
  "reason": "Run one more focused pass inside the subagent."
}

Você também pode usar o código de saída 2 e escrever o motivo da continuação em stderr.

Se algum hook SubagentStop correspondente retornar continue: false, essa decisão terá precedência sobre as decisões de continuação dos demais hooks SubagentStop correspondentes.

Stop

Atualmente, este evento não usa matcher.

Campos além dos campos de entrada comuns:

Campo Tipo Significado
turn_id string Extensão específica do Codex. ID do turno ativo do Codex
stop_hook_active boolean Indica se o turno já recebeu uma instrução de Stop para continuar
last_assistant_message string | null Mensagem mais recente do assistente, se disponível

Stop espera JSON em stdout quando termina com o código 0. Uma saída em texto simples é inválida para este evento.

O JSON enviado a stdout aceita os campos de saída comuns. Para que o Codex continue a execução, retorne:

{
  "decision": "block",
  "reason": "Run one more pass over the failing tests."
}

Você também pode usar o código de saída 2 e escrever o motivo da continuação em stderr.

Neste evento, decision: "block" não rejeita o turno. A decisão instrui o Codex a continuar e cria automaticamente um prompt de continuação que funciona como um novo prompt do usuário. O texto desse prompt é o valor de reason que você forneceu.

Se algum hook Stop correspondente retornar continue: false, essa decisão terá precedência sobre as decisões de continuação dos demais hooks Stop correspondentes.

Interrupt

Interrupt é executado quando você interrompe um turno ativo na thread principal. Use-o para registrar a interrupção ou limpar recursos usados por um trabalho iniciado por um hook. Ele não é executado para threads inativas nem para subagentes e ignora qualquer matcher configurado.

Além dos campos de entrada comuns, o evento inclui turn_id, o ID do turno interrompido, e permission_mode.

Os hooks de comando têm um tempo limite padrão de um segundo. Você pode configurar esse limite entre um e três segundos. A saída do hook não pode impedir a interrupção nem reiniciar o turno. Termine com o código 0 sem produzir saída ou retorne JSON com um systemMessage opcional para exibir um aviso. Uma saída em texto simples é inválida para este evento.

{ "systemMessage": "Saved the interrupted turn to the local audit log." }

Schemas

Os schemas da branch main disponíveis no link abaixo podem incluir campos de hooks ausentes na versão atual. Use esta página como referência para o comportamento da versão lançada.

Se precisar do formato exato dos dados transmitidos atualmente, consulte os schemas gerados no repositório do Codex no GitHub.