Hooks¶
O Aru expõe hooks em todos os pontos-chave do ciclo de vida de uma sessão. Cada hook recebe um event tipado que pode ser inspecionado ou mutado.
Tabela de hooks¶
| Hook | Quando dispara | Uso típico |
|---|---|---|
config |
Depois que a config é carregada | Ler/ajustar a config |
tool.execute.before |
Antes de qualquer tool rodar | Audit, bloquear, mutar args |
tool.execute.after |
Depois de qualquer tool rodar | Log, pós-processar resultados |
tool.definition |
Quando a lista de tools é resolvida | Modificar descrições/parâmetros |
chat.message |
Antes de uma mensagem do usuário ir ao LLM | Reescrever a mensagem |
chat.params |
Antes da chamada ao LLM | Ajustar temperature, max_tokens |
chat.system.transform |
Antes da chamada ao LLM | Modificar o system prompt |
chat.messages.transform |
Antes da chamada ao LLM | Modificar o histórico completo |
command.execute.before |
Antes de um slash command rodar | Bloquear ou reescrever |
permission.ask |
Antes de um prompt de permissão | Auto-allow/deny |
shell.env |
Antes de bash rodar |
Injetar variáveis de ambiente |
session.compact |
Antes da compactação de contexto | Reagir à compactação |
event |
Qualquer evento publicado | Inscrição genérica |
Exemplos por hook¶
config¶
@hooks.on("config")
async def tweak_config(event):
# event.config é o AgentConfig carregado
event.config.default_model = "anthropic/claude-sonnet-4-6"
tool.execute.before¶
@hooks.on("tool.execute.before")
async def audit(event):
print(f"tool={event.tool_name} args={event.args}")
if event.tool_name == "write_file" and ".env" in event.args.get("path", ""):
raise PermissionError("Writes to .env are blocked")
chat.system.transform¶
@hooks.on("chat.system.transform")
async def add_brand(event):
event.system_prompt += "\n\nAlways use metric units in examples."
chat.params¶
shell.env¶
@hooks.on("shell.env")
async def inject_secrets(event):
import os
event.env["DEPLOY_TOKEN"] = os.environ["DEPLOY_TOKEN"]
permission.ask¶
@hooks.on("permission.ask")
async def auto_allow_tests(event):
if event.tool == "bash" and event.target.startswith("pytest"):
event.decision = "allow"
command.execute.before¶
@hooks.on("command.execute.before")
async def log_commands(event):
print(f"user ran /{event.name} with args: {event.args}")
Registrando tools em plugins¶
Além dos hooks, plugins podem registrar tools diretamente no hooks.tools:
def uppercase(text: str) -> str:
"""Return text in uppercase."""
return text.upper()
hooks.tools["uppercase"] = uppercase
É equivalente a dropar um arquivo em .aru/tools/, mas permite que a tool faça parte do pacote do plugin e carregue condicionalmente.
Boas práticas¶
- Use hooks síncronos quando possível. Mesmo que o Aru suporte
async, hooks síncronos são mais rápidos e têm semântica previsível. - Não bloqueie por padrão. Hooks que levantam exceções sem motivo claro interrompem toda a sessão. Sempre deixe claro no erro por que a ação foi bloqueada.
- Cuidado com mutações do histórico.
chat.messages.transformdá poder total sobre o histórico — remover mensagens pode confundir o LLM. Prefirachat.system.transformquando possível. - Registre efeitos. Hooks que mutam state externo (envio de webhook, gravação em DB) devem logar o que fizeram — debugar plugins silenciosos é frustrante.