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

Hooks

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

Os hooks são uma estrutura de extensibilidade para o Codex. Eles permitem executar scripts ou ferramentas MCP durante o ciclo agêntico, possibilitando recursos como:

  • Enviar o chat para um sistema personalizado de logs e análise
  • Verificar os prompts da sua equipe para impedir que chaves de API sejam coladas por acidente
  • Resumir chats para criar memórias persistentes automaticamente
  • Executar uma validação personalizada quando um turno do chat terminar, garantindo o cumprimento dos padrões
  • Personalizar a criação de prompts quando estiver em um diretório específico

Durante a execução, considere o seguinte:

  • Todos os hooks correspondentes dos diferentes arquivos são executados.
  • Vários hooks de comando que correspondem ao mesmo evento são iniciados simultaneamente, por isso um hook não pode impedir que outro hook correspondente seja iniciado.
  • Hooks não gerenciados precisam ser revisados e marcados como confiáveis antes de serem executados.

Os hooks são executados em diferentes pontos de uma conversa:

QuandoHooks
Durante um turnoPreToolUse, PermissionRequest, PostToolUse, PreCompact, PostCompact, UserPromptSubmit, SubagentStop, Stop
No início de uma sessão ou de um subagenteSessionStart, SubagentStart
Quando a conversa principal terminaSessionEnd (não é executado para subagentes)

Onde o Codex procura hooks

O Codex encontra hooks junto às camadas de configuração ativas em uma destas formas:

  • hooks.json
  • tabelas [hooks] definidas diretamente em config.toml

Os plug-ins instalados também podem incluir configurações do ciclo de vida por meio do manifesto do plug-in ou de um arquivo hooks/hooks.json padrão. Consulte Criar plug-ins para ver as regras de empacotamento de plug-ins.

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

  • ~/.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 com maior precedência não substituem os hooks das camadas de menor precedência. Se uma única camada contiver tanto hooks.json quanto tabelas [hooks] definidas diretamente nela, o Codex mescla as duas formas e exibe um aviso na inicialização. Prefira uma única representação por camada.

O Codex também pode encontrar hooks incluídos em plug-ins ativados. Esses hooks são carregados junto com hooks de outras origens e seguem o mesmo processo de revisão e atribuição de confiança que os demais hooks não gerenciados.

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

Revisar hooks e marcá-los como confiáveis

O Codex lista os hooks configurados antes de decidir quais podem ser executados. Antes de executar um hook não gerenciado, o Codex exige que você revise a definição exata do hook e a marque como confiável. O Codex vincula esse registro de confiança ao hash atual do hook. Assim, hooks novos ou alterados são marcados para revisão e não são executados até serem considerados confiáveis.

Use /hooks na CLI para inspecionar as origens dos hooks, revisar hooks novos ou alterados, marcá-los como confiáveis ou desativar hooks não gerenciados individualmente. Se os hooks precisarem de revisão na inicialização, o Codex exibirá um aviso orientando você a abrir /hooks.

Hooks gerenciados provenientes do sistema, do MDM, da nuvem ou de requirements.toml são marcados como gerenciados, considerados confiáveis por política e não podem ser desativados no navegador de hooks do usuário.

Para uma automação pontual que já valida as origens dos hooks fora do Codex, passe --dangerously-bypass-hook-trust para executar os hooks ativados sem exigir um registro persistente de confiança nos hooks para essa execuçã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 critérios de correspondência que determina quando esse evento se aplica
  • Um ou mais manipuladores de hook 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 timeout for omitido, o Codex usa 600 segundos para a maioria dos hooks.
    • SessionEnd usa 1 segundo por padrão e aceita até 3 segundos.
  • statusMessage é opcional.
  • additionalContextLimit define quanto conteúdo de additionalContext um hook de comando pode enviar ao modelo antes de o Codex salvar o texto completo em disco e enviar uma prévia mais curta em seu lugar. Consulte Saída extensa 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 a manipuladores command e mcp_tool. Os manipuladores prompt e agent são analisados sintaticamente, mas ignorados.
  • Os comandos são executados usando o cwd da sessão como diretório de trabalho.
  • Para hooks locais do repositório, prefira resolver caminhos a partir da raiz do repositório Git, em vez de usar um caminho relativo como .codex/hooks/.... O Codex pode ser iniciado em um subdiretório, e um caminho baseado na raiz do repositório Git mantém estável a localização do hook.

Configuração TOML equivalente definida diretamente em 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 usa o mesmo processo de revisão e atribuiçã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 verifique cada patch após o Codex gravar ou editar 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"
          }
        ]
      }
    ]
  }
}
CampoSignificado
typeDeve ser mcp_tool.
serverNome obrigatório de um servidor MCP já conectado.
toolNome obrigatório de uma ferramenta exposta por esse servidor.
inputObjeto JSON opcional com modelos de argumentos. O padrão é {}.
timeoutTempo limite opcional de execução ativa, em segundos. O padrão é 600.
statusMessageMensagem opcional exibida enquanto o hook é executado.

Expandir argumentos a partir do evento do hook

Use ${field.nested} para ler um campo do evento do hook com notação de ponto. Um marcador de posição que ocupa todo o valor mantém seu tipo JSON. Um marcador de posição dentro de uma string maior é renderizado como 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}"
}

torna-se:

{
  "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.
  • Aplica-se o menor tempo limite entre o hook e o servidor. O tempo de espera por uma resposta de elicitação MCP não é contabilizado nesse limite.
  • Os hooks SessionStart podem ser executados antes que um servidor MCP esteja pronto. Se isso acontecer, eles não bloqueiam a sessão.
  • SessionEnd não oferece suporte a hooks de ferramentas MCP.

Desativar hooks

Os hooks são ativados por padrão. Para desativá-los em config.toml, defina:

[features]
hooks = false

Use hooks como a chave canônica do recurso. codex_hooks ainda funciona como um nome alternativo obsoleto. Os administradores podem forçar a desativação dos hooks da mesma forma em requirements.toml com [features].hooks = false.

Hooks gerenciados de requirements.toml

Os requisitos gerenciados pela empresa também podem definir hooks diretamente em [hooks]. Isso é útil quando os administradores querem impor a configuração dos hooks e, ao mesmo tempo, distribuir os scripts por MDM ou outro sistema de gerenciamento de dispositivos. Para impor hooks gerenciados mesmo para usuários que desativaram os hooks localmente, fixe [features].hooks = true em requirements.toml junto com [hooks]. Para ignorar hooks de usuário, projeto, sessão e plug-ins, mas ainda permitir 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 em managed_dir; as ferramentas da sua empresa devem instalá-los e atualizá-los separadamente.
  • Os comandos de hooks gerenciados devem usar caminhos absolutos para scripts dentro do diretório gerenciado configurado.
  • allow_managed_hooks_only = true ignora hooks de usuário, projeto, sessão e plug-ins, mas ainda carrega os hooks gerenciados de requirements.toml e de outras camadas de configuração gerenciadas.

Hooks incluídos em plug-ins

Quando um plug-in é ativado, o Codex pode carregar hooks de ciclo de vida desse plug-in junto com hooks de usuário, de projeto e gerenciados.

Por padrão, o Codex procura hooks/hooks.json na raiz do plug-in. O manifesto de um plug-in pode substituir esse padrão com uma entrada hooks em .codex-plugin/plugin.json. A entrada do manifesto 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 de hooks no manifesto são resolvidos em relação à raiz do plug-in e devem permanecer dentro dessa raiz. Se um manifesto definir hooks, o Codex usa essas entradas do manifesto em vez do arquivo padrão hooks/hooks.json.

Os comandos dos hooks de plug-ins recebem estas variáveis do ambiente:

  • PLUGIN_ROOT é uma extensão específica do Codex que aponta para a raiz do plug-in instalado.
  • PLUGIN_DATA é uma extensão específica do Codex que aponta para o diretório gravável de dados do plug-in.
  • O Codex também define CLAUDE_PLUGIN_ROOT e CLAUDE_PLUGIN_DATA para manter a compatibilidade com hooks de plug-ins existentes.

Os hooks de plug-ins usam o mesmo esquema de eventos que os outros hooks. Instalar ou ativar um plug-in não torna seus hooks automaticamente confiáveis; o Codex ignora os hooks incluídos no plug-in até que você revise a definição atual do hook e a marque como confiável.

Padrões de correspondência

O campo matcher é uma string com uma expressão regular que filtra quando os hooks são acionados. Use "*", "" ou omita completamente matcher para corresponder a todas as ocorrências de um evento com suporte.

Somente alguns eventos atuais do Codex usam matcher:

EventoO que matcher filtraObservações
PermissionRequestnome da ferramentaHá suporte para Bash, apply_patch* e nomes de ferramentas MCP
PostToolUsenome da ferramentaConsulte Cobertura de ferramentas
PostCompactacionador da compactaçãoOs valores são manual ou auto
PreCompactacionador da compactaçãoOs valores são manual ou auto
PreToolUsenome da ferramentaConsulte Cobertura de ferramentas
SessionEndmotivo do encerramentoNo momento, somente other
SessionStartorigem da inicializaçãoOs valores são startup, resume, clear e compact
SubagentStarttipo de subagenteOs valores dependem do subagente que inicia a execução
SubagentStoptipo de subagenteOs valores dependem do subagente que encerra a execução
UserPromptSubmitsem suporteQualquer matcher configurado é ignorado neste evento
Stopsem suporteQualquer matcher configurado é ignorado neste evento

*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
  • manual|auto

Cobertura de ferramentas

PreToolUse e PostToolUse podem observar outros tipos de chamada além de chamadas de shell e MCP. A maioria das ferramentas de função locais usa o mesmo caminho de execução dos hooks. Assim, você pode filtrar pelo nome da ferramenta, inspecionar seus argumentos JSON e, no caso de PreToolUse, bloquear ou reescrever a chamada.

Caminho da ferramentaPreToolUsePostToolUseObservações
Comandos de shellSimSimUse Bash como critério de correspondência.
Execução unificada (exec_command)SimSimUse Bash como critério de correspondência. Uma consulta posterior com write_stdin pode entregar o evento PostToolUse do comando original quando esse comando terminar.
apply_patchSimSimUse apply_patch, Edit ou Write como critério de correspondência.
Ferramentas MCPSimSimUse o nome da ferramenta MCP, como mcp__filesystem__read_file, para a correspondência.
Outras ferramentas de função locaisSimSimUse o nome da ferramenta de função, como update_plan, para a correspondência. spawn_agent também corresponde a Agent.
Ferramentas hospedadas, como WebSearchNãoNãoEssas ferramentas não usam o caminho de hooks das ferramentas de função locais.

write_stdin fornece o 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 caminhos especializados de execução de ferramentas podem não usar o caminho padrão de hooks. Trate os hooks de ferramentas como uma proteção útil, não como uma garantia de que todas as regras serão aplicadas.

Campos comuns de entrada

Cada hook de comando recebe um objeto JSON em stdin.

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

CampoTipoSignificado
session_idstringID da sessão atual do Codex. Os hooks de subagentes usam o ID da sessão pai.
transcript_pathstring | nullCaminho do arquivo de transcrição da sessão, se houver
cwdstringDiretório de trabalho da sessão
hook_event_namestringNome do evento de hook atual
modelstringExtensão específica do Codex. Slug do modelo ativo

Os hooks com escopo de turno listam turn_id como uma extensão específica do Codex nas tabelas dos respectivos eventos.

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

transcript_path aponta para uma transcrição do chat por conveniência, mas 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 Esquemas.

Campos comuns de saída

SessionStart, PreCompact, PostCompact, UserPromptSubmit, SubagentStop e Stop oferecem suporte a estes campos JSON compartilhados. 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
}
CampoEfeito
continueSe for false, marca essa execução do hook como interrompida
stopReasonRegistrado como motivo da interrupção
systemMessageExibido como aviso na interface ou no fluxo de eventos
suppressOutputInterpretado atualmente, mas ainda não implementado

O encerramento com código 0 e sem saída é considerado bem-sucedido, e o Codex continua.

PreToolUse e PermissionRequest oferecem suporte a systemMessage, mas atualmente não há suporte a continue, stopReason e suppressOutput nesses eventos. Se um hook PreToolUse retornar um desses campos sem suporte, o Codex marca essa execução do hook como malsucedida, informa o erro e prossegue com a chamada da ferramenta.

PostToolUse oferece suporte a systemMessage, continue: false e stopReason. suppressOutput é interpretado, mas atualmente não há 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 aproximadamente 2.500 tokens. Se um hook retornar mais conteúdo, o Codex salva o texto completo em <temp_dir>/hook_outputs/<session_id>/<uuid>.txt e fornece ao modelo uma prévia com o início e o fim do conteúdo, junto com o caminho do arquivo salvo. Esse comportamento é chamado de transferência para disco: o Codex armazena em disco as saídas acima do limite e as substitui por uma prévia mais curta, visível ao modelo. Se não for possível gravar o arquivo, o modelo ainda recebe uma prévia truncada.

Mantenha conciso o contexto fornecido por hooks e plug-ins. O contexto de vários hooks e plug-ins se acumula e pode prejudicar o desempenho do modelo. Aumentar additionalContextLimit eleva esse risco. Evite definir o limite como 0, a menos que o hook imponha um limite máximo rígido à saída; caso contrário, um único hook poderá consumir toda a janela de contexto.

Para qualquer hook de comando que retorne additionalContext, defina additionalContextLimit no manipulador para personalizar 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 número inteiro positivo para selecionar outro limite ou 0 para repassar todo o contexto adicional do manipulador diretamente ao modelo. O Codex avalia cada manipulador correspondente de forma independente. Nos eventos que não podem gerar contexto adicional, o Codex ignora additionalContextLimit e emite um aviso de configuração.

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

Como saídas acima do limite podem ser gravadas em disco, evite retornar segredos ou outros dados sensíveis na saída do hook.

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 declarado diretamente em config.toml, defina async = true:

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

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

A entrada, o critério de correspondência, a revisão de confiança, o tempo limite e o tratamento de saídas grandes são os mesmos nos hooks em segundo plano e nos hooks de comando síncronos. Assim como nos outros hooks de comando, timeout é medido em segundos e tem o valor padrão 600.

Como os hooks em segundo plano são executados

Quando um hook em segundo plano termina, o Codex entrega a saída informativa compatível no próximo ponto seguro da conversa:

  • Se houver um turno ativo, o Codex aguarda a conclusão da solicitação atual ao modelo e das chamadas de ferramentas. Em seguida, disponibiliza a saída para a próxima solicitação ao modelo nesse turno.
  • Se nenhum turno estiver ativo, o Codex aguarda 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 um aviso.

Os 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 políticas de ferramentas, decisões de permissão, rejeição de prompts ou continuação de turnos.

Limitações

  • O Codex executa até oito hooks em segundo plano simultaneamente por sessão. Os hooks adicionais aguardam até que um hook em execução termine.
  • Cada invocação correspondente é executada de forma independente, e 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 foram concluídos e descarta a saída que ainda não foi entregue.
  • Os hooks SessionEnd sempre são executados de forma síncrona.

Hooks

SessionStart

matcher é aplicado a source neste evento.

Além dos campos de entrada comuns, há estes campos:

CampoTipoSignificado
sourcestringComo a sessão foi iniciada: startup, resume, clear ou compact

O texto simples em stdout é adicionado como contexto adicional do desenvolvedor.

O JSON em 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."
  }
}

Esse texto de additionalContext é adicionado como contexto adicional do 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 se aplica quando a compactação automática ocorre no meio de um turno: o Codex entrega o contexto adicional do hook à continuação imediata, em vez de aguardar 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 as notas finais ou limpar arquivos. Ele é executado para a conversa principal quando você arquiva ou exclui uma conversa que ainda está aberta, quando o Codex é encerrado normalmente ou depois que uma conversa fica inativa e não está aberta em nenhum cliente conectado por 30 minutos. Ele não é executado para subagentes.

Sair de uma conversa ou chamar thread/unsubscribe não encerra a sessão imediatamente, por isso SessionEnd não é executado de imediato. Seu hook ainda pode ler a transcrição da sessão durante a execução.

matcher filtra reason neste evento. Por enquanto, reason é sempre other. Você pode omitir matcher ou usar other para executar em todos os eventos SessionEnd.

Além dos campos de entrada comuns, há estes campos:

CampoTipoSignificado
reasonstringMotivo 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. Eles têm caráter apenas informativo, portanto sua saída não orienta o Codex nem mantém a conversa aberta. Se um comando atingir o tempo limite ou terminar com erro, o Codex relata isso como uma falha do hook.

SubagentStart

matcher é aplicado a agent_type neste evento.

Além dos campos de entrada comuns, há estes campos:

CampoTipoSignificado
turn_idstringExtensão específica do Codex. ID do turno ativo do Codex
agent_idstringIdentificador do subagente
agent_typestringTipo ou perfil do subagente
permission_modestringModo de permissão atual

O texto simples em stdout é adicionado como contexto adicional do desenvolvedor para o subagente.

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

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

Esse texto de additionalContext é adicionado como contexto adicional do desenvolvedor para o subagente. continue: false é analisado para fins de compatibilidade, mas não impede que o subagente seja iniciado.

PreToolUse

PreToolUse pode interceptar Bash, edições de arquivos realizadas por meio de apply_patch, chamadas de ferramentas MCP e outras ferramentas de função locais. Consulte Cobertura de ferramentas para ver os caminhos compatíveis e as exceções.

matcher é aplicado a tool_name e aos nomes alternativos usados na correspondência. Para edições de arquivos por meio de apply_patch, os valores de matcher podem ser apply_patch, Edit ou Write; a entrada do hook continua informando tool_name: "apply_patch".

Além dos campos de entrada comuns, há estes campos:

CampoTipoSignificado
turn_idstringExtensão específica do Codex. ID do turno ativo do Codex
tool_namestringNome canônico da ferramenta no hook, como Bash, apply_patch ou um nome MCP como mcp__fs__read
tool_use_idstringID da chamada de ferramenta nesta invocação
tool_inputJSON valueEntrada específica da ferramenta. Bash e apply_patch usam tool_input.command. As ferramentas MCP e outras ferramentas de função locais enviam seus argumentos.

O texto simples em stdout é ignorado.

O JSON em 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 esta estrutura de bloqueio mais antiga:

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

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

Para adicionar contexto visível para o modelo sem bloquear, 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 MCP e outras ferramentas de função locais, updatedInput é o objeto de argumentos substituto. Retorne updatedInput apenas com permissionDecision: "allow"; outros formatos de updatedInput são relatados como erros.

permissionDecision: "ask", a forma legada decision: "approve", continue: false, stopReason e suppressOutput são analisados sintaticamente, mas ainda não têm suporte. O Codex marca a execução do hook como malsucedida, relata o erro e dá continuidade à chamada de ferramenta.

PermissionRequest

PermissionRequest é executado quando o Codex está prestes a pedir aprovação, como para uma elevação de permissões no shell ou uma aprovação de acesso à rede gerenciada. Ele pode permitir a solicitação, negá-la ou se abster de decidir e deixar que o prompt normal de aprovação prossiga. Ele não é executado para comandos que não precisam de aprovação.

matcher é aplicado a tool_name e aos aliases de correspondência. Os valores canônicos atuais incluem Bash, apply_patch e nomes de ferramentas MCP, como mcp__server__tool; apply_patch também corresponde a Edit e Write.

Outros campos, além dos campos de entrada comuns:

CampoTipoSignificado
turn_idstringExtensão específica do Codex. ID do turno ativo do Codex
tool_namestringNome canônico da ferramenta no hook, como Bash, apply_patch ou um nome de ferramenta MCP, como mcp__fs__read
tool_inputJSON valueEntrada específica da ferramenta. Bash e apply_patch usam tool_input.command, enquanto as ferramentas MCP enviam todos os argumentos.
tool_input.descriptionstring | nullMotivo da aprovação em linguagem natural, quando fornecido pelo Codex

O texto simples em stdout é ignorado.

Algumas entradas de ferramentas podem incluir uma descrição em linguagem natural, mas não presuma que o campo tool_input.description esteja presente 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 prevalece. Caso contrário, allow permite que a solicitação prossiga sem exibir o prompt de aprovação. Se nenhum hook correspondente decidir, o Codex usa o fluxo normal de aprovação.

Não retorne updatedInput, updatedPermissions ou interrupt para PermissionRequest; esses campos estão reservados para comportamentos futuros e, atualmente, resultam em bloqueio por segurança.

PostToolUse

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

matcher é aplicado a tool_name e aos aliases de correspondência. Para edições de arquivos por meio de apply_patch, os valores de matcher podem ser apply_patch, Edit ou Write; a entrada do hook continua informando tool_name: "apply_patch".

Outros campos, além dos campos de entrada comuns:

CampoTipoSignificado
turn_idstringExtensão específica do Codex. ID do turno ativo do Codex
tool_namestringNome canônico da ferramenta no hook, como Bash, apply_patch ou um nome de ferramenta MCP, como mcp__fs__read
tool_use_idstringID da chamada de ferramenta desta invocação
tool_inputJSON valueEntrada específica da ferramenta. Bash e apply_patch usam tool_input.command. As ferramentas MCP e outras ferramentas de função locais enviam seus argumentos.
tool_responseJSON valueSaída específica da ferramenta. As ferramentas MCP enviam o resultado da chamada MCP. Outras ferramentas de função locais normalmente enviam a saída apresentada ao modelo.

O texto simples em stdout é ignorado.

O JSON em 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."
  }
}

Esse texto de additionalContext é adicionado como contexto adicional do desenvolvedor.

Neste evento, decision: "block" não desfaz o comando Bash já concluído. Em vez disso, 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 gravar o motivo do feedback em stderr.

Para interromper o processamento normal do resultado original da ferramenta depois que o comando já tiver sido executado, retorne continue: false. O Codex substituirá o resultado da ferramenta pelo seu feedback ou pelo texto de interrupção e continuará a partir daí.

updatedMCPToolOutput e suppressOutput são analisados sintaticamente, mas ainda não têm suporte. O Codex marca a execução do hook como malsucedida, relata o erro e continua o processamento normal do resultado da ferramenta.

Chamadas de ferramentas no modo de código

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

Resultado do hookO que o modo de código vê
PreToolUse bloqueiaA promessa da ferramenta é rejeitada antes da execução da ferramenta.
PreToolUse retorna updatedInputA ferramenta é executada com a entrada reescrita, e a promessa é resolvida com esse resultado.
PostToolUse retorna decision: "block" ou termina com o código de saída 2A ferramenta é executada e, em seguida, a promessa é rejeitada com o motivo fornecido pelo hook.
PostToolUse retorna continue: falseO Codex usa o feedback do hook como resultado visível para o modelo, mas não rejeita a promessa da chamada de ferramenta aninhada.

PreCompact

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

Outros campos, além dos campos de entrada comuns:

CampoTipoSignificado
turn_idstringExtensão específica do Codex. ID do turno ativo do Codex
triggerstringO que acionou a compactação: manual ou auto

O texto simples em stdout é ignorado.

O JSON em stdout oferece suporte aos campos de saída comuns. Se um hook PreCompact correspondente retornar continue: false, o Codex interrompe o processo antes da compactação.

PostCompact

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

Outros campos, além dos campos de entrada comuns:

CampoTipoSignificado
turn_idstringExtensão específica do Codex. ID do turno ativo do Codex
triggerstringO que acionou a compactação: manual ou auto

O texto simples em stdout é ignorado.

O JSON em stdout oferece suporte aos campos comuns de saída. Se um hook PostCompact correspondente retornar continue: false, o Codex para após a compactação.

UserPromptSubmit

matcher não é usado atualmente para este evento.

Campos além dos campos comuns de entrada:

CampoTipoSignificado
turn_idstringExtensão específica do Codex. ID do turno ativo do Codex
promptstringPrompt do usuário que está prestes a ser enviado

O texto simples em stdout é adicionado como contexto adicional do desenvolvedor.

O JSON em stdout oferece suporte aos campos comuns de saída e a esta estrutura específica do hook:

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

Esse texto de additionalContext é adicionado como contexto adicional do 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 gravar o motivo do bloqueio em stderr.

SubagentStop

matcher é aplicado a agent_type neste evento.

Campos além dos campos comuns de entrada:

CampoTipoSignificado
turn_idstringExtensão específica do Codex. ID do turno ativo do Codex
agent_idstringIdentificador do subagente
agent_typestringTipo ou perfil do subagente
agent_transcript_pathstring | nullCaminho para o arquivo de transcrição do subagente, se houver
stop_hook_activebooleanIndica se este subagente já continuou a execução
last_assistant_messagestring | nullMensagem mais recente do assistente do subagente, se disponível

SubagentStop espera receber JSON em stdout ao encerrar com o código 0. A saída em texto simples é inválida para este evento.

O JSON em stdout oferece suporte aos campos comuns de saída. Para pedir ao Codex que continue o fluxo 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 gravar o motivo da continuação em stderr.

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

Stop

matcher não é usado atualmente para este evento.

Campos além dos campos comuns de entrada:

CampoTipoSignificado
turn_idstringExtensão específica do Codex. ID do turno ativo do Codex
stop_hook_activebooleanIndica se este turno já teve continuidade por meio de Stop
last_assistant_messagestring | nullTexto da mensagem mais recente do assistente, se disponível

Stop espera receber JSON em stdout ao encerrar com o código 0. A saída em texto simples é inválida para este evento.

O JSON em stdout oferece suporte aos campos comuns de saída. Para que o Codex continue, 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 gravar o motivo da continuação em stderr.

Neste evento, decision: "block" não rejeita o turno. Em vez disso, instrui o Codex a continuar e cria automaticamente um novo prompt de continuação que funciona como um novo prompt do usuário, usando o valor de reason como texto desse prompt.

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

Esquemas

Os esquemas da branch main indicados nos links podem incluir campos de hooks que não fazem parte da versão atual. Use esta página como referência para o comportamento da versão.

Se precisar do formato de transmissão exato usado atualmente, consulte os esquemas gerados no repositório do Codex no GitHub.