Plugins
Ganchos de Plugin
Hooks de Plugin são pontos de extensão em processo para plugins do OpenClaw. Use-os quando um plugin precisa inspecionar ou alterar execuções de agentes, chamadas de ferramenta, fluxo de mensagens, ciclo de vida de sessões, roteamento de subagentes, instalações ou inicialização do Gateway.
Use hooks internos em vez disso quando você quiser um pequeno
script HOOK.md instalado pelo operador para eventos de comando e Gateway, como
/new, /reset, /stop, agent:bootstrap ou gateway:startup.
Início rápido
Registre hooks de Plugin tipados com api.on(...) a partir da entrada do seu plugin:
export default definePluginEntry({
id: "tool-preflight",
name: "Tool Preflight",
register(api) {
api.on(
"before_tool_call",
async (event) => {
if (event.toolName !== "web_search") {
return;
}
return {
requireApproval: {
title: "Run web search",
description: `Allow search query: ${String(event.params.query ?? "")}`,
severity: "info",
timeoutMs: 60_000,
timeoutBehavior: "deny",
},
};
},
{ priority: 50 },
);
},
});
Os manipuladores de hook são executados sequencialmente em ordem decrescente de priority. Hooks com a mesma prioridade
mantêm a ordem de registro.
api.on(name, handler, opts?) aceita:
priority- ordenação do manipulador (valores maiores executam primeiro).timeoutMs- orçamento opcional por hook. Quando definido, o executor de hooks aborta esse manipulador depois que o orçamento expira e continua com o próximo, em vez de permitir que configuração lenta ou trabalho de recuperação consumam o tempo limite de modelo configurado pelo chamador. Omita para usar o tempo limite padrão de observação/decisão que o executor de hooks aplica genericamente.
Operadores também podem definir orçamentos de hook sem modificar o código do plugin:
{
"plugins": {
"entries": {
"my-plugin": {
"hooks": {
"timeoutMs": 30000,
"timeouts": {
"before_prompt_build": 90000,
"agent_end": 60000
}
}
}
}
}
}
hooks.timeouts.<hookName> substitui hooks.timeoutMs, que substitui o valor
api.on(..., { timeoutMs }) escrito pelo plugin. Cada valor configurado deve
ser um número inteiro positivo não maior que 600000 milissegundos. Prefira
substituições por hook para hooks sabidamente lentos, para que um plugin não receba um orçamento maior
em todos os lugares.
Cada hook recebe event.context.pluginConfig, a configuração resolvida para o
plugin que registrou aquele manipulador. Use-a para decisões de hook que precisam das
opções atuais do plugin; o OpenClaw a injeta por manipulador sem alterar o
objeto de evento compartilhado visto por outros plugins.
Catálogo de hooks
Os hooks são agrupados pela superfície que estendem. Nomes em negrito aceitam um resultado de decisão (bloquear, cancelar, substituir ou exigir aprovação); todos os outros são somente observação.
Turno do agente
before_model_resolve- substitui o provedor ou modelo antes que as mensagens da sessão sejam carregadasagent_turn_prepare- consome injeções de turno de plugin enfileiradas e adiciona contexto do mesmo turno antes dos hooks de promptbefore_prompt_build- adiciona contexto dinâmico ou texto de prompt de sistema antes da chamada ao modelobefore_agent_start- fase combinada apenas para compatibilidade; prefira os dois hooks acimabefore_agent_run- inspeciona o prompt final e as mensagens da sessão antes do envio ao modelo e opcionalmente bloqueia a execuçãobefore_agent_reply- interrompe o turno do modelo com uma resposta sintética ou silênciobefore_agent_finalize- inspeciona a resposta final natural e solicita mais uma passagem do modeloagent_end- observa mensagens finais, estado de sucesso e duração da execuçãoheartbeat_prompt_contribution- adiciona contexto somente de Heartbeat para monitor em segundo plano e plugins de ciclo de vida
Observação da conversa
model_call_started/model_call_ended- observa metadados higienizados de chamada de provedor/modelo, temporização, resultado e hashes delimitados de ID de solicitação sem conteúdo de prompt ou respostallm_input- observa entrada do provedor (prompt de sistema, prompt, histórico)llm_output- observa saída do provedor
Ferramentas
before_tool_call- reescreve parâmetros de ferramenta, bloqueia a execução ou exige aprovaçãoafter_tool_call- observa resultados de ferramenta, erros e duraçãotool_result_persist- reescreve a mensagem do assistente produzida a partir de um resultado de ferramentabefore_message_write- inspeciona ou bloqueia uma gravação de mensagem em andamento (raro)
Mensagens e entrega
inbound_claim- reivindica uma mensagem de entrada antes do roteamento do agente (respostas sintéticas)message_received- observa conteúdo de entrada, remetente, conversa e metadadosmessage_sending- reescreve conteúdo de saída ou cancela a entregamessage_sent- observa sucesso ou falha na entrega de saídabefore_dispatch- inspeciona ou reescreve um despacho de saída antes da passagem para o canalreply_dispatch- participa do pipeline final de despacho de resposta
Sessões e Compaction
session_start/session_end- acompanha limites do ciclo de vida da sessãobefore_compaction/after_compaction- observa ou anota ciclos de Compactionbefore_reset- observa eventos de redefinição de sessão (/reset, redefinições programáticas)
Subagentes
subagent_spawning/subagent_delivery_target/subagent_spawned/subagent_ended- coordena roteamento de subagentes e entrega de conclusão
Ciclo de vida
gateway_start/gateway_stop- inicia ou interrompe serviços pertencentes ao plugin com o Gatewaycron_changed- observa mudanças no ciclo de vida de Cron pertencente ao Gateway (adicionado, atualizado, removido, iniciado, finalizado, agendado)before_install- inspeciona varreduras de instalação de skill ou plugin e opcionalmente bloqueia
Política de chamada de ferramenta
before_tool_call recebe:
event.toolNameevent.paramsevent.runIdopcionalevent.toolCallIdopcional- campos de contexto como
ctx.agentId,ctx.sessionKey,ctx.sessionId,ctx.runId,ctx.jobId(definido em execuções acionadas por cron) ectx.tracediagnóstico
Ele pode retornar:
type BeforeToolCallResult = {
params?: Record<string, unknown>;
block?: boolean;
blockReason?: string;
requireApproval?: {
title: string;
description: string;
severity?: "info" | "warning" | "critical";
timeoutMs?: number;
timeoutBehavior?: "allow" | "deny";
pluginId?: string;
onResolution?: (
decision: "allow-once" | "allow-always" | "deny" | "timeout" | "cancelled",
) => Promise<void> | void;
};
};
Regras:
block: trueé terminal e ignora manipuladores de prioridade mais baixa.block: falseé tratado como ausência de decisão.paramsreescreve os parâmetros da ferramenta para execução.requireApprovalpausa a execução do agente e pergunta ao usuário por meio de aprovações de plugin. O comando/approvepode aprovar tanto aprovações de exec quanto de plugin.- Um
block: truede prioridade mais baixa ainda pode bloquear depois que um hook de prioridade mais alta solicitou aprovação. onResolutionrecebe a decisão de aprovação resolvida -allow-once,allow-always,deny,timeoutoucancelled.
Plugins incluídos que precisam de política em nível de host podem registrar políticas de ferramenta confiáveis
com api.registerTrustedToolPolicy(...). Elas são executadas antes dos hooks
before_tool_call comuns e antes das decisões de plugins externos. Use-as somente
para barreiras confiáveis pelo host, como política de workspace, aplicação de orçamento ou
segurança de fluxos de trabalho reservados. Plugins externos devem usar hooks before_tool_call
normais.
Persistência de resultado de ferramenta
Resultados de ferramenta podem incluir details estruturados para renderização de UI, diagnósticos,
roteamento de mídia ou metadados pertencentes ao plugin. Trate details como metadados de runtime,
não como conteúdo de prompt:
- O OpenClaw remove
toolResult.detailsantes da reprodução para o provedor e da entrada de Compaction para que metadados não virem contexto do modelo. - Entradas de sessão persistidas mantêm apenas
detailsdelimitados. Detalhes grandes demais são substituídos por um resumo compacto epersistedDetailsTruncated: true. tool_result_persistebefore_message_writesão executados antes do limite final de persistência. Ainda assim, hooks devem manterdetailsretornados pequenos e evitar colocar texto relevante para o prompt somente emdetails; coloque a saída de ferramenta visível ao modelo emcontent.
Hooks de prompt e modelo
Use os hooks específicos de fase para novos plugins:
before_model_resolve: recebe apenas o prompt atual e metadados de anexo. RetorneproviderOverrideoumodelOverride.agent_turn_prepare: recebe o prompt atual, mensagens de sessão preparadas e quaisquer injeções enfileiradas de execução única esvaziadas para esta sessão. RetorneprependContextouappendContext.before_prompt_build: recebe o prompt atual e as mensagens da sessão. RetorneprependContext,appendContext,systemPrompt,prependSystemContextouappendSystemContext.heartbeat_prompt_contribution: é executado apenas para turnos de Heartbeat e retornaprependContextouappendContext. Ele é destinado a monitores em segundo plano que precisam resumir o estado atual sem alterar turnos iniciados pelo usuário.
before_agent_start permanece por compatibilidade. Prefira os hooks explícitos acima
para que seu plugin não dependa de uma fase combinada legada.
before_agent_run é executado após a construção do prompt e antes de qualquer entrada de modelo,
incluindo carregamento de imagens locais ao prompt e observação llm_input. Ele recebe
a entrada atual do usuário como prompt, além do histórico de sessão carregado em messages
e o prompt de sistema ativo. Retorne { outcome: "block", reason, message? }
para interromper a execução antes que o modelo possa ler o prompt. reason é interno;
message é a substituição voltada ao usuário. Os únicos resultados compatíveis são
pass e block; formatos de decisão não compatíveis falham em modo fechado.
Quando uma execução é bloqueada, o OpenClaw armazena apenas o texto substituto em
message.content, além de metadados de bloqueio não sensíveis, como o ID do plugin
bloqueador e o carimbo de data/hora. O texto original do usuário não é retido na transcrição nem em contexto
futuro. Motivos internos de bloqueio são tratados como sensíveis e excluídos de
transcrição, histórico, transmissão, log e cargas de diagnóstico. Observabilidade
deve usar campos higienizados, como ID do bloqueador, resultado, carimbo de data/hora ou uma categoria
segura.
before_agent_start e agent_end incluem event.runId quando o OpenClaw consegue
identificar a execução ativa. O mesmo valor também está disponível em ctx.runId.
Execuções acionadas por Cron também expõem ctx.jobId (o ID do job de cron de origem) para que
hooks de plugin possam limitar métricas, efeitos colaterais ou estado a um job agendado
específico.
Para execuções originadas por canal, ctx.messageProvider é a superfície do provedor, como
discord ou telegram, enquanto ctx.channelId é o identificador do alvo da conversa
quando o OpenClaw consegue derivá-lo da chave de sessão ou dos metadados de
entrega.
agent_end é um hook de observação e executa em fire-and-forget depois do turno. O
executor de hooks aplica um tempo limite de 30 segundos para que um plugin travado ou endpoint de
embedding não deixe a promessa do hook pendente para sempre. Um tempo limite é registrado e
o OpenClaw continua; ele não cancela trabalho de rede pertencente ao plugin, a menos que o
plugin também use seu próprio sinal de abortamento.
Use model_call_started e model_call_ended para telemetria de chamadas de provedor
que não deve receber prompts brutos, histórico, respostas, cabeçalhos, corpos de solicitação
ou IDs de solicitação do provedor. Esses hooks incluem metadados estáveis, como
runId, callId, provider, model, api/transport opcional,
durationMs/outcome terminal e upstreamRequestIdHash quando o OpenClaw consegue derivar um
hash delimitado de ID de solicitação do provedor.
before_agent_finalize é executado apenas quando um harness está prestes a aceitar uma
resposta final natural do assistente. Ele não é o caminho de cancelamento /stop e não
é executado quando o usuário aborta um turno. Retorne { action: "revise", reason } para pedir
ao harness mais uma passagem do modelo antes da finalização, { action: "finalize", reason? } para forçar a finalização, ou omita um resultado para continuar.
Hooks Stop nativos do Codex são encaminhados para este hook como decisões
before_agent_finalize do OpenClaw.
Ao retornar action: "revise", plugins podem incluir metadados retry para tornar
a passagem extra do modelo delimitada e segura para reprodução:
type BeforeAgentFinalizeRetry = {
instruction: string;
idempotencyKey?: string;
maxAttempts?: number;
};
instruction é anexado ao motivo da revisão enviado ao harness.
idempotencyKey permite que o host conte novas tentativas para a mesma solicitação do plugin entre
decisões de finalização equivalentes, e maxAttempts limita quantas passagens extras o
host permitirá antes de continuar com a resposta final natural.
Plugins não incluídos no pacote que precisam de ganchos de conversa bruta (before_model_resolve,
before_agent_reply, llm_input, llm_output, before_agent_finalize,
agent_end ou before_agent_run) devem definir:
{
"plugins": {
"entries": {
"my-plugin": {
"hooks": {
"allowConversationAccess": true
}
}
}
}
}
Ganchos que modificam prompts e injeções duráveis no próximo turno podem ser desabilitados por plugin
com plugins.entries.<id>.hooks.allowPromptInjection=false.
Extensões de sessão e injeções no próximo turno
Plugins de fluxo de trabalho podem persistir pequenos estados de sessão compatíveis com JSON usando
api.registerSessionExtension(...) e atualizá-los pelo método Gateway
sessions.pluginPatch. Linhas de sessão projetam o estado de extensão registrado
por meio de pluginExtensions, permitindo que a Control UI e outros clientes renderizem
status de propriedade do plugin sem conhecer os componentes internos do plugin.
Use api.enqueueNextTurnInjection(...) quando um plugin precisar que contexto durável
chegue ao próximo turno do modelo exatamente uma vez. O OpenClaw esvazia as injeções enfileiradas antes dos
ganchos de prompt, descarta injeções expiradas e desduplica por idempotencyKey
por plugin. Esta é a interface correta para retomadas de aprovação, resumos de políticas,
deltas de monitores em segundo plano e continuações de comandos que devem ser visíveis para
o modelo no próximo turno, mas não devem se tornar texto permanente do prompt do sistema.
As semânticas de limpeza fazem parte do contrato. Callbacks de limpeza de extensão de sessão e
de ciclo de vida de runtime recebem reset, delete, disable ou
restart. O host remove o estado persistente de extensão de sessão do plugin proprietário
e as injeções pendentes do próximo turno para reset/delete/disable; restart mantém
o estado durável da sessão enquanto callbacks de limpeza permitem que plugins liberem tarefas
do agendador, contexto de execução e outros recursos fora de banda da geração antiga
do runtime.
Ganchos de mensagem
Use ganchos de mensagem para roteamento em nível de canal e política de entrega:
message_received: observe conteúdo de entrada, remetente,threadId,messageId,senderId, correlação opcional de execução/sessão e metadados.message_sending: reescrevacontentou retorne{ cancel: true }.message_sent: observe sucesso ou falha final.
Para respostas TTS somente em áudio, content pode conter a transcrição falada oculta
mesmo quando a carga do canal não tem texto/legenda visível. Reescrever esse
content atualiza apenas a transcrição visível ao gancho; ela não é renderizada como
legenda de mídia.
Contextos de ganchos de mensagem expõem campos de correlação estáveis quando disponíveis:
ctx.sessionKey, ctx.runId, ctx.messageId, ctx.senderId, ctx.trace,
ctx.traceId, ctx.spanId, ctx.parentSpanId e ctx.callDepth. Prefira
esses campos de primeira classe antes de ler metadados legados.
Prefira os campos tipados threadId e replyToId antes de usar metadados específicos do canal.
Regras de decisão:
message_sendingcomcancel: trueé terminal.message_sendingcomcancel: falseé tratado como sem decisão.contentreescrito continua para ganchos de menor prioridade, a menos que um gancho posterior cancele a entrega.
Ganchos de instalação
before_install é executado depois da varredura integrada para instalações de Skills e plugins.
Retorne achados adicionais ou { block: true, blockReason } para interromper a
instalação.
block: true é terminal. block: false é tratado como sem decisão.
Ciclo de vida do Gateway
Use gateway_start para serviços de plugin que precisam de estado pertencente ao Gateway. O
contexto expõe ctx.config, ctx.workspaceDir e ctx.getCron?.() para
inspeção e atualizações de cron. Use gateway_stop para limpar recursos
de longa duração.
Não dependa do gancho interno gateway:startup para serviços de runtime
pertencentes ao plugin.
cron_changed dispara para eventos de ciclo de vida de cron pertencentes ao Gateway com uma carga
de evento tipada cobrindo os motivos added, updated, removed, started, finished
e scheduled. O evento carrega um instantâneo PluginHookGatewayCronJob
(incluindo state.nextRunAtMs, state.lastRunStatus e
state.lastError quando presente), além de um PluginHookGatewayCronDeliveryStatus
de not-requested | delivered | not-delivered | unknown. Eventos removidos
ainda carregam o instantâneo da tarefa excluída para que agendadores externos possam
reconciliar o estado. Use ctx.getCron?.() e ctx.config do contexto de runtime
ao sincronizar agendadores externos de despertar, e mantenha o OpenClaw como a
fonte da verdade para verificações de vencimento e execução.
Próximas descontinuações
Algumas superfícies adjacentes a ganchos foram descontinuadas, mas ainda têm suporte. Migre antes da próxima versão principal:
- Envelopes de canal em texto puro em manipuladores
inbound_claimemessage_received. LeiaBodyForAgente os blocos estruturados de contexto do usuário em vez de analisar texto de envelope plano. Consulte Envelopes de canal em texto puro → BodyForAgent. before_agent_startpermanece por compatibilidade. Novos plugins devem usarbefore_model_resolveebefore_prompt_buildem vez da fase combinada.onResolutionembefore_tool_callagora usa a união tipadaPluginApprovalResolution(allow-once/allow-always/deny/timeout/cancelled) em vez de umastringde formato livre.
Para a lista completa - registro de capacidade de memória, perfil de raciocínio de provedor,
provedores externos de autenticação, tipos de descoberta de provedor, acessadores de runtime
de tarefas e a renomeação command-auth → command-status - consulte
Migração do Plugin SDK → Descontinuações ativas.
Relacionados
- Migração do Plugin SDK - descontinuações ativas e cronograma de remoção
- Criando plugins
- Visão geral do Plugin SDK
- Pontos de entrada de plugin
- Ganchos internos
- Componentes internos da arquitetura de plugins