Hooks
Hooks
Execute scripts determinísticos durante o ciclo de vida do Codex
Os hooks são uma estrutura de extensibilidade para o Codex. Permitem executar scripts ou ferramentas MCP durante o ciclo de agentes, possibilitando funcionalidades como:
- Enviar a conversa para um motor personalizado de registo/análise
- Analisar os prompts da sua equipa para impedir a colagem acidental de API keys
- Resumir conversas para criar automaticamente memórias persistentes
- Executar uma verificação de validação personalizada quando um turno de conversa termina, impondo normas
- Personalizar os prompts quando estiver num determinado diretório
Comportamento em tempo de execução a ter em conta:
- Todos os hooks correspondentes de vários ficheiros são executados.
- Vários hooks de comando correspondentes ao mesmo evento são iniciados em simultâneo, pelo que um hook não pode impedir o início de outro hook correspondente.
- Os hooks não geridos têm de ser revistos e considerados fidedignos antes de serem executados.
Os hooks são executados em diferentes momentos de uma conversa:
| Quando | Hooks |
|---|---|
| Durante um turno | PreToolUse, PermissionRequest, PostToolUse, PreCompact, PostCompact, UserPromptSubmit, SubagentStop, Stop |
| Quando interrompe um turno ativo | Interrupt (não é executado para subagentes) |
| Quando uma sessão ou subagente inicia | SessionStart, SubagentStart |
| Quando a thread principal termina | SessionEnd (não é executado para subagentes) |
Onde o Codex procura hooks
O Codex descobre hooks junto das camadas de configuração ativas, numa destas formas:
hooks.json- tabelas
[hooks]inline dentro deconfig.toml
Os plugins instalados também podem incluir a configuração do ciclo de vida através do respetivo
manifesto ou de um ficheiro hooks/hooks.json predefinido. Consulte Criar
plugins para conhecer as
regras de empacotamento de plugins.
Na prática, as quatro localizações mais úteis são:
~/.codex/hooks.json~/.codex/config.toml<repo>/.codex/hooks.json<repo>/.codex/config.toml
Se existir mais do que 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 hooks.json e [hooks] inline, o Codex
combina-os e apresenta um aviso no arranque. Prefira uma representação por camada.
O Codex também pode descobrir hooks incluídos em plugins ativados. Os hooks incluídos em plugins são carregados juntamente com outras origens de hooks e utilizam o mesmo fluxo de revisão de confiança que os restantes hooks não geridos.
Os hooks locais do projeto só são carregados quando a camada .codex/ do projeto é considerada fidedigna. Em
projetos não fidedignos, o Codex continua a carregar hooks do utilizador e do sistema a partir das respetivas
camadas de configuração ativas.
Rever e considerar hooks fidedignos
O Codex apresenta uma lista dos hooks configurados antes de decidir quais podem ser executados. Antes de um hook não gerido poder ser executado, o Codex exige que reveja e considere fidedigna a definição exata do hook. O Codex regista a confiança relativamente ao hash atual do hook, pelo que os hooks novos ou alterados são assinalados para revisão e ignorados até serem considerados fidedignos.
Utilize /hooks na CLI para inspecionar as origens dos hooks, rever hooks novos ou alterados,
considerar hooks fidedignos ou desativar hooks não geridos individuais. Se existirem hooks que necessitem de revisão no
arranque, o Codex apresenta um aviso que lhe indica que deve abrir /hooks.
Os hooks geridos provenientes de origens do sistema, MDM, cloud ou requirements.toml são assinalados
como geridos, considerados fidedignos por política e não podem ser desativados no navegador de hooks do utilizador.
Para automatizações pontuais que já validem as origens dos hooks fora do Codex, transmita
--dangerously-bypass-hook-trust para executar os hooks ativados sem exigir
confiança persistente nos hooks para essa invocação.
Estrutura da configuração
Os hooks estão organizados em três níveis:
- Um evento de hook, como
PreToolUse,PostToolUse,PreCompact,SubagentStartouStop - Um grupo de correspondência que decide quando esse evento corresponde
- Um ou mais processadores de hooks que são executados quando o grupo de correspondência corresponde
{
"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
}
]
}
]
}
}Notas:
descriptionconsiste em metadados opcionais de nível superior para um ficheirohooks.json. Não altera os hooks que são executados.timeouté expresso em segundos.- Se
timeoutfor omitido, o Codex utiliza600segundos para a maioria dos hooks.SessionEndeInterruptutilizam1segundo por predefinição e suportam até3segundos.
statusMessageé opcional.additionalContextLimitdefine a quantidade deadditionalContextque um hook de comando pode enviar ao modelo antes de o Codex guardar o texto completo no disco e enviar, em alternativa, uma pré-visualização mais curta. Consulte Saída extensa de hooks.commandWindowsé uma substituição opcional do comando, exclusiva do Windows. Em TOML, utilizecommand_windowsoucommandWindows.- Defina
asynccomotruepara executar um hook de comando em segundo plano. - São suportados processadores
commandemcp_tool. Os processadoresprompteagentsão analisados, mas ignorados. - Os comandos são executados com o
cwdda sessão como diretório de trabalho. - Para hooks locais do repositório, dê preferência à resolução a partir da raiz do git, em vez de utilizar um
caminho relativo como
.codex/hooks/.... O Codex pode ser iniciado a partir de um subdiretório, e um caminho baseado na raiz do git mantém estável a localização do hook.
TOML inline equivalente 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 invoque uma ferramenta num servidor MCP já ligado. Envia argumentos estruturados diretamente para a ferramenta e utiliza a mesma revisão de confiança e o mesmo contrato de resultados que um hook de comando.
Configurar um hook de ferramenta MCP
Este hook solicita ao servidor MCP scanner que analise cada patch depois de o Codex escrever ou
editar ficheiros:
{
"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 |
Tem de ser mcp_tool. |
server |
Nome obrigatório de um servidor MCP já ligado. |
tool |
Nome obrigatório de uma ferramenta exposta por esse servidor. |
input |
Objeto JSON opcional de modelos de argumentos. A predefinição é {}. |
timeout |
Limite de tempo opcional da execução ativa, em segundos. A predefinição é 600. |
statusMessage |
Mensagem opcional apresentada durante a execução do hook. |
Expandir argumentos a partir do evento do hook
Utilize ${field.nested} para ler um campo com notação de pontos a partir do evento do hook. Um marcador de posição
que preencha um valor inteiro mantém o respetivo tipo JSON. Um marcador de posição dentro de uma string
maior é apresentado como texto. O Codex expande objetos e matrizes recursivamente.
Para um evento que contenha {"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}"
}transforma-se em:
{
"path": "src/main.rs",
"count": 3,
"message": "Scanning src/main.rs"
}Execução e ciclo de vida
- Os hooks utilizam uma ligação MCP existente. Não iniciam nem voltam a ligar servidores.
- Um hook pode bloquear uma operação quando a ferramenta devolve uma decisão de bloqueio. Os erros, servidores em falta e ferramentas indisponíveis não bloqueiam a operação.
- Os hooks de ferramentas MCP são executados de forma síncrona. Não solicitam aprovação da ferramenta nem acionam outros hooks.
- Aplica-se o limite de tempo mais curto do hook ou do servidor. O tempo de espera por uma resposta de elicitação MCP não é contabilizado no limite de tempo.
- Os hooks
SessionStartpodem ser executados antes de um servidor MCP estar pronto. Se isso acontecer, não bloqueiam a sessão. SessionEndnão suporta hooks de ferramentas MCP.
Desativar os hooks
Os hooks estão ativados por predefinição. Para os desativar em config.toml, defina:
[features]
hooks = falseUtilize hooks como chave canónica da funcionalidade. codex_hooks continua a funcionar como
alias preterido. Os administradores podem forçar a desativação dos hooks da mesma forma em
requirements.toml com [features].hooks = false.
Hooks geridos a partir de requirements.toml
Os requisitos geridos pela empresa também podem definir hooks inline em [hooks].
Isto é útil quando os administradores pretendem impor a configuração dos hooks, enquanto
fornecem os próprios scripts através de MDM ou de outro sistema de gestão de dispositivos.
Para impor hooks geridos mesmo aos utilizadores que desativaram os hooks localmente, fixe
[features].hooks = true em requirements.toml juntamente com [hooks]. Para ignorar
hooks do utilizador, do projeto, da sessão e de plugins, permitindo ainda assim hooks geridos 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"Notas sobre hooks geridos:
managed_diré utilizado no macOS e Linux.windows_managed_diré utilizado no Windows.- O Codex não distribui os scripts em
managed_dir; as ferramentas da sua empresa têm de os instalar e atualizar separadamente. - Os comandos de hooks geridos devem utilizar caminhos absolutos de scripts no diretório gerido configurado.
allow_managed_hooks_only = trueignora hooks provenientes de origens do utilizador, do projeto, da sessão e de plugins, mas continua a carregar hooks geridos a partir derequirements.tomle de outras camadas de configuração geridas.
Hooks incluídos em plugins
Quando um plugin está ativado, o Codex pode carregar hooks do ciclo de vida desse plugin juntamente com hooks do utilizador, do projeto e geridos.
Por predefinição, o Codex procura hooks/hooks.json dentro da raiz do plugin. Um manifesto de
plugin pode substituir essa predefinição com uma entrada hooks em
.codex-plugin/plugin.json. A entrada do manifesto pode ser um caminho com o prefixo ./, uma
matriz de caminhos com o prefixo ./, um objeto de hooks inline ou uma matriz de objetos de
hooks inline.
{
"name": "repo-policy",
"hooks": "./hooks/hooks.json"
}Os caminhos de hooks do manifesto são resolvidos relativamente à raiz do plugin e têm de permanecer
dentro dessa raiz. Se um manifesto definir hooks, o Codex utiliza essas entradas do manifesto
em vez do hooks/hooks.json predefinido.
Os comandos de 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 gravável do plugin.- O Codex também define
CLAUDE_PLUGIN_ROOTeCLAUDE_PLUGIN_DATApara compatibilidade com hooks de plugins existentes.
Os hooks de plugins utilizam o mesmo esquema de eventos que os restantes hooks. Instalar ou ativar um plugin não torna automaticamente fidedignos os respetivos hooks; o Codex ignora os hooks incluídos no plugin até que reveja e considere fidedigna a definição atual do hook.
Padrões de correspondência
O campo matcher é uma string de expressão regular que filtra quando os hooks são acionados. Utilize "*",
"" ou omita totalmente matcher para corresponder a todas as ocorrências de um evento
suportado.
Apenas alguns eventos atuais do Codex respeitam matcher:
| Evento | O que matcher filtra |
Notas |
|---|---|---|
PermissionRequest |
nome da ferramenta | O suporte inclui Bash, apply_patch* e nomes de ferramentas MCP |
PostToolUse |
nome da ferramenta | Consulte Cobertura de ferramentas |
PostCompact |
acionador de compactação | Os valores são manual ou auto |
PreCompact |
acionador de compactação | Os valores são manual ou auto |
PreToolUse |
nome da ferramenta | Consulte Cobertura de ferramentas |
SessionEnd |
motivo do fim | Atualmente, apenas other |
SessionStart |
origem do início | Os valores são startup, resume, clear e compact |
SubagentStart |
tipo de subagente | Os valores dependem do subagente que inicia |
SubagentStop |
tipo de subagente | Os valores dependem do subagente que termina |
UserPromptSubmit |
não suportado | Qualquer matcher configurado é ignorado para este evento |
Stop |
não suportado | Qualquer matcher configurado é ignorado para este evento |
Interrupt |
não suportado | Qualquer matcher configurado é ignorado para este evento |
*Para apply_patch, os valores de matcher também podem utilizar Edit ou Write.
Exemplos:
Bash^apply_patch$Edit|Writemcp__filesystem__read_filemcp__filesystem__.*startup|resume|clear|compactmanual|auto
Cobertura das ferramentas
PreToolUse e PostToolUse podem observar mais do que chamadas de shell e MCP. A maioria das
ferramentas de função locais utiliza o mesmo caminho de hooks, pelo que pode estabelecer correspondência com o nome da ferramenta,
inspecionar os respetivos argumentos JSON e, no caso de PreToolUse, bloquear ou reescrever a chamada.
| Caminho da ferramenta | PreToolUse |
PostToolUse |
Notas |
|---|---|---|---|
| Comandos de shell | Sim | Sim | Corresponde como Bash. |
Execução unificada (exec_command) |
Sim | Sim | Corresponde como Bash. Uma consulta write_stdin posterior pode fornecer o PostToolUse do comando original quando esse comando terminar. |
apply_patch |
Sim | Sim | Corresponde como apply_patch, Edit ou Write. |
| Ferramentas MCP | Sim | Sim | Corresponde ao nome da ferramenta MCP, como mcp__filesystem__read_file. |
| Outras ferramentas de função locais | Sim | Sim | Corresponde ao nome da ferramenta de função, como update_plan. spawn_agent também corresponde a Agent. |
Ferramentas alojadas, como WebSearch |
Não | Não | Estas não utilizam o caminho de hooks de ferramentas de função locais. |
write_stdin é o transporte para uma sessão de execução unificada existente. Não executa
PreToolUse novamente quando envia dados ou consulta um comando que já passou por
PreToolUse.
Alguns caminhos de ferramentas especializados podem optar por não utilizar o caminho de hooks predefinido. Considere os hooks de ferramentas uma proteção útil, não um limite de imposição completo.
Campos de entrada comuns
Cada hook de comando recebe um objeto JSON em stdin.
Estes são os campos partilhados que utilizará habitualmente:
| Campo | Tipo | Significado |
|---|---|---|
session_id |
string |
ID da sessão atual do Codex. Os hooks de subagentes utilizam o ID da sessão principal. |
transcript_path |
string | null |
Caminho para o ficheiro de transcrição da sessão, se existir |
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 âmbito de turno apresentam turn_id como uma extensão específica do Codex nas respetivas
tabelas específicas do evento.
SessionStart, PreToolUse, PermissionRequest, PostToolUse,
UserPromptSubmit, SubagentStart, SubagentStop, Stop e Interrupt também incluem
permission_mode, que descreve o modo de permissões atual como default,
acceptEdits, plan, dontAsk ou bypassPermissions.
transcript_path aponta para uma transcrição da conversa por conveniência, mas o
formato da transcrição não é uma interface estável para hooks e pode mudar ao longo do tempo.
Se precisar do formato de transmissão completo, consulte Esquemas.
Campos de saída comuns
SessionStart, PreCompact, PostCompact, UserPromptSubmit,
SubagentStop e Stop suportam estes campos JSON partilhados. 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, assinala essa execução do hook como interrompida |
stopReason |
Registado como motivo da interrupção |
systemMessage |
Apresentado como aviso na IU ou no fluxo de eventos |
suppressOutput |
Atualmente analisado, mas ainda não implementado |
A saída com 0 sem resultados é considerada um êxito e o Codex continua.
PreToolUse e PermissionRequest suportam systemMessage, mas continue,
stopReason e suppressOutput não são atualmente suportados para esses eventos.
Se um hook PreToolUse devolver um desses campos não suportados, o Codex assinala
essa execução do hook como falhada, comunica o erro e continua a chamada da ferramenta.
PostToolUse suporta systemMessage, continue: false e stopReason.
suppressOutput é analisado, mas não é atualmente suportado para esse evento.
Resultados extensos de hooks
Por predefinição, o Codex limita cada mensagem de resultados de hooks visível para o modelo a cerca de
2 500 tokens. Se um hook devolver mais, o Codex guarda o texto completo em
<temp_dir>/hook_outputs/<session_id>/<uuid>.txt e fornece ao modelo uma
pré-visualização do início e do fim com o caminho do ficheiro guardado. Este comportamento chama-se
spilling: o Codex armazena no disco os resultados de tamanho excessivo e substitui-os por uma
pré-visualização mais curta, visível para o modelo. Se não for possível escrever o ficheiro, o modelo continua a
receber uma pré-visualização truncada.
Para qualquer hook de comando que devolva additionalContext, defina
additionalContextLimit no processador para personalizar o limiar aproximado de
tokens:
{
"type": "command",
"command": "python3 ~/.codex/hooks/session_start.py",
"additionalContextLimit": 5000
}Omita additionalContextLimit para utilizar o limiar predefinido de 2500 tokens. Utilize um
número inteiro positivo para selecionar um limiar diferente ou 0 para transmitir o contexto
adicional completo do processador diretamente ao modelo. O Codex avalia cada processador
correspondente de forma independente. Para eventos que não podem produzir contexto adicional,
o Codex ignora additionalContextLimit e comunica um aviso de configuração.
A definição aplica-se apenas a additionalContext. O feedback das ferramentas e os prompts de continuação
mantêm o limite predefinido.
Uma vez que os resultados de tamanho excessivo podem ser escritos no disco, evite devolver segredos ou outros dados sensíveis nos resultados dos hooks.
Executar hooks em segundo plano
Por predefinição, o Codex aguarda que um hook de comando termine antes de prosseguir com a
operação que o acionou. Defina async como true para executar um hook de comando em
segundo plano enquanto o Codex continua.
Configurar um hook em segundo plano
Adicione "async": true a um processador de comandos 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 inline 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 = 120Os hooks em segundo plano utilizam a mesma entrada, correspondência, análise de confiança, tempo limite e
processamento de saídas extensas que os hooks de comando síncronos. Tal como
noutros hooks de comando, timeout é medido em segundos e a predefinição é
600. Os hooks Interrupt utilizam uma predefinição de um segundo e um máximo de três segundos,
inclusive quando são executados em segundo plano.
Como são executados os hooks em segundo plano
Quando um hook em segundo plano termina, o Codex fornece os resultados informativos suportados no ponto seguro seguinte da conversa:
- Se estiver ativo um turno, o Codex aguarda que o pedido atual ao modelo e as chamadas de ferramentas terminem e, em seguida, disponibiliza os resultados ao pedido seguinte ao modelo nesse turno.
- Se não estiver ativo nenhum turno, o Codex aguarda até ao turno seguinte do utilizador. A conclusão de um hook em segundo plano não inicia um novo turno.
Utilize a mesma saída JSON específica do evento que utilizaria num hook síncrono. O Codex adiciona
additionalContext ao contexto do modelo e apresenta systemMessage como
aviso.
Limitações
- O Codex executa até oito hooks em segundo plano em simultâneo 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 numa ordem diferente daquela em que começaram.
- Quando a sessão termina, o Codex cancela os hooks em segundo plano não concluídos e elimina os resultados que não tenham sido fornecidos.
- Os hooks
SessionEndsão sempre executados de forma síncrona.
Hooks
SessionStart
matcher é aplicado a source neste evento.
Campos além dos Campos de entrada comuns:
| Campo | Tipo | Significado |
|---|---|---|
source |
string |
Como a sessão começou: startup, resume, clear ou compact |
O texto simples em stdout é adicionado como contexto de programador adicional.
O JSON em stdout suporta Campos de saída comuns e esta
estrutura específica do hook:
{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": "Load the workspace conventions before editing."
}
}Esse texto additionalContext é adicionado como contexto de programador adicional.
Depois de o Codex compactar uma sessão raiz, os hooks SessionStart que correspondam a
source: "compact" são executados antes do pedido seguinte ao modelo. Isto também se aplica quando a
compactação automática ocorre a meio de um turno: o Codex fornece o contexto adicional do hook
à continuação imediata, em vez de aguardar por um turno posterior do utilizador. Se o hook
devolver continue: false, o Codex termina o turno sem enviar outro pedido ao modelo.
SessionEnd
SessionEnd permite executar um comando quando uma sessão termina, por exemplo, para guardar notas
finais ou limpar ficheiros. É executado no thread principal quando arquiva ou elimina uma
conversa que ainda está aberta, quando o Codex fecha normalmente ou depois de uma
conversa estar inativa e não estar aberta em nenhum cliente ligado durante 30
minutos. Não é executado para subagentes.
Mudar para outra conversa ou invocar thread/unsubscribe não termina
a sessão de imediato, pelo que não executará imediatamente SessionEnd. O hook ainda pode
ler a transcrição da sessão durante a execução.
matcher filtra reason neste evento. Por enquanto, reason é sempre other.
Pode omitir matcher ou utilizar other para executar em todos os eventos SessionEnd.
Campos além dos Campos de entrada comuns:
| Campo | Tipo | Significado |
|---|---|---|
reason |
string |
Motivo pelo qual a sessão terminou: 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 são sempre executados de forma síncrona, mesmo quando async é true. São
consultivos, pelo que os respetivos resultados não orientarão o Codex nem manterão o thread aberto. Se um
comando exceder o limite de tempo ou terminar com um erro, o Codex comunica-o como uma falha do hook.
SubagentStart
matcher é aplicado a agent_type neste evento.
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 em stdout é adicionado como contexto de programador adicional para o subagente.
O JSON em stdout suporta systemMessage e esta estrutura específica do hook:
{
"hookSpecificOutput": {
"hookEventName": "SubagentStart",
"additionalContext": "Review the repository test conventions first."
}
}Esse texto additionalContext é adicionado como contexto de programador adicional para o
subagente. continue: false é analisado para fins de compatibilidade, mas não impede o
início do subagente.
PreToolUse
PreToolUse pode intercetar Bash, edições de ficheiros efetuadas através de apply_patch,
chamadas de ferramentas MCP e outras ferramentas de função locais. Consulte Cobertura das
ferramentas para conhecer os caminhos suportados e as exceções.
matcher é aplicado a tool_name e aos aliases de correspondência. Para edições de ficheiros através de
apply_patch, os valores de matcher podem utilizar apply_patch, Edit ou Write; a entrada do hook
continua a comunicar 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 do hook, como Bash, apply_patch ou um nome MCP como mcp__fs__read |
tool_use_id |
string |
ID da chamada da ferramenta para esta invocação |
tool_input |
JSON value |
Entrada específica da ferramenta. Bash e apply_patch utilizam tool_input.command. As ferramentas MCP e outras ferramentas de função locais enviam os respetivos argumentos. |
O texto simples em stdout é ignorado.
O JSON em stdout pode utilizar systemMessage. Para recusar uma chamada de ferramenta suportada, devolva
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."
}Também pode utilizar o código de saída 2 e escrever o motivo do bloqueio em stderr.
Para adicionar contexto visível para o modelo sem bloquear, devolva
hookSpecificOutput.additionalContext:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"additionalContext": "The pending command touches generated files."
}
}Para reescrever uma chamada de ferramenta suportada sem a bloquear, devolva
permissionDecision: "allow" com updatedInput:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow",
"updatedInput": {
"command": "echo rewritten"
}
}
}Para comandos Bash e apply_patch, updatedInput tem de incluir um campo de string
command. Para MCP e outras ferramentas de função locais, updatedInput é o
objeto de argumentos substituto. Devolva updatedInput apenas com
permissionDecision: "allow"; outras estruturas de updatedInput são comunicadas como
erros.
permissionDecision: "ask", o decision: "approve" legado, continue: false,
stopReason e suppressOutput são analisados, mas ainda não são suportados. O Codex assinala
a execução do hook como falhada, comunica o erro e continua a chamada da ferramenta.
PermissionRequest
PermissionRequest é executado quando o Codex está prestes a pedir aprovação, por exemplo, para uma
escalada do shell ou aprovação da rede gerida. Pode permitir o pedido, recusar
o pedido ou não tomar uma decisão e deixar que o pedido de aprovação normal continue.
Não é executado para comandos que não necessitem 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.
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 do 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 utilizam tool_input.command, enquanto as ferramentas MCP enviam todos os argumentos. |
tool_input.description |
string | null |
Motivo da aprovação legível por humanos, quando o Codex dispõe de um |
O texto simples em stdout é ignorado.
Algumas entradas de ferramentas podem incluir uma descrição legível por humanos, mas não dependa de um
campo tool_input.description para todas as ferramentas.
Para aprovar o pedido, devolva:
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "allow"
}
}
}Para recusar o pedido, devolva:
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "deny",
"message": "Blocked by repository policy."
}
}
}Se vários hooks correspondentes devolverem decisões, qualquer deny prevalece. Caso contrário, um
allow permite que o pedido prossiga sem apresentar o pedido de aprovação. Se nenhum
hook correspondente tomar uma decisão, o Codex utiliza o fluxo de aprovação normal.
Não devolva updatedInput, updatedPermissions nem interrupt para
PermissionRequest; esses campos estão reservados para comportamento futuro e atualmente provocam
uma falha fechada.
PostToolUse
PostToolUse é executado depois de as ferramentas suportadas produzirem resultados, incluindo Bash,
apply_patch, chamadas de ferramentas MCP e outras ferramentas de função locais. Para Bash, também
é executado após comandos que terminem com um estado diferente de zero. Não pode desfazer efeitos
secundários de uma ferramenta que já tenha sido executada. Consulte Cobertura das ferramentas para
conhecer os caminhos suportados e as exceções.
matcher é aplicado a tool_name e aos aliases de correspondência. Para edições de ficheiros através de
apply_patch, os valores de matcher podem utilizar apply_patch, Edit ou Write; a entrada do hook
continua a comunicar 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 do hook, como Bash, apply_patch ou um nome MCP como mcp__fs__read |
tool_use_id |
string |
ID da chamada da ferramenta para esta invocação |
tool_input |
JSON value |
Entrada específica da ferramenta. Bash e apply_patch utilizam tool_input.command. As ferramentas MCP e outras ferramentas de função locais enviam os respetivos 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 enviam normalmente os respetivos resultados dirigidos ao modelo. |
O texto simples em stdout é ignorado.
O JSON em stdout pode utilizar 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 additionalContext é adicionado como contexto de programador adicional.
Neste evento, decision: "block" não desfaz o comando Bash concluído.
Em vez disso, o Codex regista o feedback, substitui o resultado da ferramenta por esse
feedback e faz o modelo continuar a partir da mensagem fornecida pelo hook.
Também pode utilizar 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 depois de o comando já
ter sido executado, devolva continue: false. O Codex substituirá o resultado da ferramenta pelo
seu feedback ou texto de interrupção e continuará a partir daí.
updatedMCPToolOutput e suppressOutput são analisados, mas ainda não são suportados.
O Codex assinala a execução do hook como falhada, comunica o erro e continua o processamento
normal do resultado da ferramenta.
Chamadas de ferramentas no modo de código
Quando um modelo utiliza o modo de código para invocar uma ferramenta a partir de JavaScript, as decisões dos hooks aplicam-se
a essa chamada aninhada. PreToolUse pode interromper a ferramenta antes de esta ser executada ou reescrever
a respetiva entrada. Um PostToolUse de bloqueio não pode desfazer os efeitos secundários 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 de a ferramenta ser executada. |
PreToolUse devolve updatedInput |
A ferramenta é executada com a entrada reescrita e a promessa é resolvida com esse resultado. |
PostToolUse devolve decision: "block" ou termina com o código 2 |
A ferramenta é executada e, em seguida, a promessa é rejeitada com o motivo do hook. |
PostToolUse devolve continue: false |
O Codex utiliza o feedback do hook para o resultado visível para o modelo, mas não rejeita a promessa da ferramenta aninhada. |
PreCompact
PreCompact é executado antes de o Codex compactar a conversa. matcher é aplicado
a 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 texto simples em stdout é ignorado.
O JSON em stdout suporta Campos de saída comuns. Se um
hook PreCompact correspondente devolver continue: false, o Codex para antes de
compactar.
PostCompact
PostCompact é executado depois de o Codex compactar a conversa. matcher é aplicado
a 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 texto simples em stdout é ignorado.
O JSON em stdout suporta Campos de saída comuns. Se um
hook PostCompact correspondente devolver continue: false, o Codex para depois de
compactar.
UserPromptSubmit
matcher não é atualmente utilizado neste evento.
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 utilizador que está prestes a ser enviado |
O texto simples em stdout é adicionado como contexto de programador adicional.
O JSON em stdout suporta Campos de saída comuns e
esta estrutura específica do hook:
{
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": "Ask for a clearer reproduction before editing files."
}
}Esse texto additionalContext é adicionado como contexto de programador adicional.
Para bloquear o prompt, devolva:
{
"decision": "block",
"reason": "Ask for confirmation before doing that."
}Também pode utilizar o código de saída 2 e escrever o motivo do bloqueio em stderr.
SubagentStop
matcher é aplicado a agent_type neste evento.
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 para o ficheiro de transcrição do subagente, se existir |
stop_hook_active |
boolean |
Se este subagente já foi continuado |
last_assistant_message |
string | null |
Mensagem mais recente do assistente do subagente, se disponível |
SubagentStop espera JSON em stdout quando termina com 0. A saída em texto simples é
inválida para este evento.
O JSON em stdout suporta Campos de saída comuns. Para pedir
ao Codex que continue o fluxo do subagente, devolva:
{
"decision": "block",
"reason": "Run one more focused pass inside the subagent."
}Também pode utilizar o código de saída 2 e escrever o motivo da continuação em stderr.
Se qualquer hook SubagentStop correspondente devolver continue: false, isso tem
precedência sobre as decisões de continuação de outros hooks SubagentStop
correspondentes.
Stop
matcher não é atualmente utilizado neste evento.
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 |
Se este turno já foi continuado por Stop |
last_assistant_message |
string | null |
Texto da mensagem mais recente do assistente, se disponível |
Stop espera JSON em stdout quando termina com 0. A saída em texto simples é inválida
para este evento.
O JSON em stdout suporta Campos de saída comuns. Para manter
o Codex em execução, devolva:
{
"decision": "block",
"reason": "Run one more pass over the failing tests."
}Também pode utilizar 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. Em vez disso, indica
ao Codex que continue e cria automaticamente um novo prompt de continuação que funciona
como um novo prompt do utilizador, utilizando o seu reason como texto desse prompt.
Se qualquer hook Stop correspondente devolver continue: false, isso tem precedência
sobre as decisões de continuação de outros hooks Stop correspondentes.
Interrupt
Interrupt é executado quando interrompe um turno ativo na thread principal. Utilize-o
para registar a interrupção ou limpar o trabalho iniciado por um hook. Não é executado
para threads inativas nem para subagentes, e qualquer matcher configurado é ignorado.
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, por predefinição, um tempo limite de um segundo. Os tempos limite configurados estão
limitados a um a três segundos. A saída do hook não pode impedir a
interrupção nem reiniciar o turno. Termine com 0 sem saída ou devolva JSON com
um systemMessage opcional para apresentar um aviso. A saída de texto simples é inválida
para este evento.
{ "systemMessage": "Saved the interrupted turn to the local audit log." }Esquemas
Se precisar do formato de transmissão atual exato, consulte os esquemas gerados no repositório GitHub do Codex.
Aliases de texto simples
- string | null