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:
| Quando | Hooks |
|---|---|
| Durante um turno | PreToolUse, PermissionRequest, PostToolUse, PreCompact, PostCompact, UserPromptSubmit, SubagentStop, Stop |
| No início de uma sessão ou de um subagente | SessionStart, SubagentStart |
| Quando a conversa principal termina | SessionEnd (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 emconfig.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,SubagentStartouStop - 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 arquivohooks.json. Ele não altera quais hooks são executados.timeouté expresso em segundos.- Se
timeoutfor omitido, o Codex usa600segundos para a maioria dos hooks.SessionEndusa1segundo por padrão e aceita até3segundos.
statusMessageé opcional.additionalContextLimitdefine quanto conteúdo deadditionalContextum 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, usecommand_windowsoucommandWindows.- Defina
asynccomotruepara executar um hook de comando em segundo plano. - Há suporte a manipuladores
commandemcp_tool. Os manipuladoresprompteagentsão analisados sintaticamente, mas ignorados. - Os comandos são executados usando o
cwdda 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"
}
]
}
]
}
}
| Campo | Significado |
|---|---|
type | Deve ser mcp_tool. |
server | Nome obrigatório de um servidor MCP já conectado. |
tool | Nome obrigatório de uma ferramenta exposta 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 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
SessionStartpodem ser executados antes que um servidor MCP esteja pronto. Se isso acontecer, eles não bloqueiam a sessão. SessionEndnã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 = trueignora hooks de usuário, projeto, sessão e plug-ins, mas ainda carrega os hooks gerenciados derequirements.tomle 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_ROOTeCLAUDE_PLUGIN_DATApara 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:
| 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 Cobertura de ferramentas |
PostCompact | acionador da compactação | Os valores são manual ou auto |
PreCompact | acionador da compactação | Os valores são manual ou auto |
PreToolUse | nome da ferramenta | Consulte Cobertura de ferramentas |
SessionEnd | motivo do encerramento | No momento, somente other |
SessionStart | origem da inicialização | Os valores são startup, resume, clear e compact |
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 | Qualquer matcher configurado é ignorado neste evento |
Stop | sem suporte | Qualquer matcher configurado é ignorado neste evento |
*Para apply_patch, os valores de matcher também podem ser Edit ou Write.
Exemplos:
Bash^apply_patch$Edit|Writemcp__filesystem__read_filemcp__filesystem__.*startup|resume|clear|compactmanual|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 ferramenta | PreToolUse | PostToolUse | Observações |
|---|---|---|---|
| Comandos de shell | Sim | Sim | Use Bash como critério de correspondência. |
Execução unificada (exec_command) | Sim | Sim | Use 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_patch | Sim | Sim | Use apply_patch, Edit ou Write como critério de correspondência. |
| Ferramentas MCP | Sim | Sim | Use o nome da ferramenta MCP, como mcp__filesystem__read_file, para a correspondência. |
| Outras ferramentas de função locais | Sim | Sim | Use o nome da ferramenta de função, como update_plan, para a correspondência. spawn_agent também corresponde a Agent. |
Ferramentas hospedadas, como WebSearch | Não | Não | Essas 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á:
| 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 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
}
| Campo | Efeito |
|---|---|
continue | Se for false, marca essa execução do hook como interrompida |
stopReason | Registrado como motivo da interrupção |
systemMessage | Exibido como aviso na interface ou no fluxo de eventos |
suppressOutput | Interpretado 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
SessionEndsempre 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:
| Campo | Tipo | Significado |
|---|---|---|
source | string | Como 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:
| 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. 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:
| 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 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:
| 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 no hook, como Bash, apply_patch ou um nome MCP como mcp__fs__read |
tool_use_id | string | ID da chamada de 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 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:
| 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 no hook, como Bash, apply_patch ou um nome de ferramenta 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 | Motivo 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:
| 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 no hook, como Bash, apply_patch ou um nome de ferramenta MCP, como mcp__fs__read |
tool_use_id | string | ID da chamada de ferramenta desta invocação |
tool_input | JSON value | Entrada 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_response | JSON value | Saí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 hook | O que o modo de código vê |
|---|---|
PreToolUse bloqueia | 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 esse resultado. |
PostToolUse retorna decision: "block" ou termina com o código de saída 2 | A ferramenta é executada e, 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 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:
| 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 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:
| 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 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:
| 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 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:
| 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 para o arquivo de transcrição do subagente, se houver |
stop_hook_active | boolean | Indica se este subagente já continuou a execução |
last_assistant_message | string | null | Mensagem 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:
| Campo | Tipo | Significado |
|---|---|---|
turn_id | string | Extensão específica do Codex. ID do turno ativo do Codex |
stop_hook_active | boolean | Indica se este turno já teve continuidade por meio de Stop |
last_assistant_message | string | null | Texto 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.