← voltar

🪝 Hooks

Execute scripts shell em pontos-chave do ciclo do agente — antes de uma tool rodar (PreToolUse), depois de uma tool ter sucesso (PostToolUse), ou ao terminar (Stop). O output é injetado de volta no contexto do modelo: ele vê os erros de lint, typecheck ou testes e corrige sozinho, sem intervenção humana.

🇬🇧 In short: hooks let you run shell scripts at key points in the agent loop. Output is fed back to the model so it can self-correct lint errors, type errors, and failing tests — no human in the loop required.

Como funciona

Modelo decide chamar uma tool
PreToolUse
→ bloqueia se exit ≠ 0
Tool executa (write_file, run_command…)
PostToolUse
→ stdout injetado no contexto
Modelo lê output → corrige no próximo turno
Stop
→ ao chamar finish

Eventos

PreToolUse

Antes da tool executar

Se o script retornar exit code ≠ 0, a tool é bloqueada e o output vira mensagem de erro para o modelo.

  • Bloquear comandos perigosos (rm -rf)
  • Validar argumentos antes de escrever
  • Garantir ambiente pronto
PostToolUse

Após tool bem-sucedida

stdout+stderr do script são injetados no contexto — o modelo vê e pode corrigir no próximo turno.

  • Lint / typecheck automático
  • Formatar código (prettier, black)
  • Rodar testes afetados
Stop

Ao chamar finish

Roda depois da verificação passar, antes de retornar o resultado. Sem contexto de tool — use {workspace}.

  • Commit automático das mudanças
  • Notificar via Slack / webhook
  • Gerar changelog / release notes

Configuração

Crie .poly/hooks.json na raiz do projeto (ou ~/.polypus/hooks.json para configuração global):

{ "hooks": [ { "event": "PostToolUse", "on": ["write_file", "edit_file"], "command": "npx tsc --noEmit 2>&1 | head -30", "maxOutputChars": 2000, "timeout": 30000 }, { "event": "PostToolUse", "on": ["write_file", "edit_file"], "command": "npx eslint {path} --fix 2>&1", "maxOutputChars": 1000 } ] }
{ "hooks": [ { "event": "PostToolUse", "on": ["write_file", "edit_file"], "command": "ruff check {path} --fix 2>&1", "maxOutputChars": 1000 }, { "event": "PostToolUse", "on": ["write_file"], "command": "python -m pytest tests/ -x -q 2>&1 | tail -20", "maxOutputChars": 2000, "timeout": 60000 } ] }
{ "hooks": [ { "event": "Stop", "command": "cd {workspace} && git add -A && git diff --cached --quiet || git commit -m 'polypus: auto-commit'" }, { "event": "PreToolUse", "on": ["run_command"], "command": "echo '{tool}' | grep -q 'rm -rf' && exit 1 || exit 0" } ] }

🔒 Segurança: hooks só são carregados de ~/.polypus/hooks.json ou .poly/hooks.json do workspace — nunca de subdiretórios do repositório. Isso evita que projetos de terceiros injetem comandos maliciosos.

Visibilidade no CLI e VSCode

Cada hook aparece na timeline de eventos em tempo real. Use --compact ou pressione h para colapsar.

$ polypus run "refatorar auth para jwt"
 Polypus pensando ···
 write_file src/auth/jwt.ts0.3s
 PostToolUse npm run typecheck1.2s ✓
✓ No type errors found (3 files checked)
 edit_file src/middleware/auth.ts0.2s
 PostToolUse npm run lint0.8s ✗
✗ 2 errors: implicit any in line 14, 31
 Stop git commit1.4s ✓
[main 3a8f2c1] refactor: migrate auth to JWT
✓ Concluído · 6 steps · 1.2k tokens · $0.0031 · 9.2s

Referência de campos

CampoTipoPadrãoDescrição
eventstringPreToolUse · PostToolUse · Stop
onstring | string[]"*"Nome(s) da tool. Não usado em Stop.
commandstringComando shell. Suporta {path} {tool} {workspace}
timeoutnumber (ms)120 000Tempo máximo de execução
maxOutputCharsnumber1 000Máx chars capturados. Limite absoluto: 8 000

Substituições de variáveis

PlaceholderValorDisponível em
{path}Caminho do arquivo operadoPreToolUse, PostToolUse
{tool}Nome da tool (ex.: write_file)PreToolUse, PostToolUse
{workspace}Diretório raiz do projetoTodos

Migração do formato antigo

Os campos afterWrite, afterEdit, afterTool e beforeCommand ainda funcionam mas estão deprecated — uma mensagem de aviso é exibida no stderr ao carregar.

⚠️ Formato deprecated ainda funciona mas não receberá novos recursos. Migre para o campo hooks para ter acesso a PreToolUse, Stop, matcher por tool e controle de timeout/output.

// Antes (deprecated) { "afterWrite": "npm run lint", "beforeCommand": { "deny": ["rm -rf"] } } // Depois { "hooks": [ { "event": "PostToolUse", "on": ["write_file", "edit_file"], "command": "npm run lint" }, { "event": "PreToolUse", "on": ["run_command"], "command": "echo '{tool}' | grep -q 'rm -rf' && exit 1 || exit 0" } ] }