fangdididi/trigger-rehearsal

Ensaiar as regras de gatilho de um agente orientado por eventos ou em segundo plano antes de ativá-las. Converte qualquer formato de regra (arquivos de regras de hubs de agentes, rotinas, blocos 'on:' de CI, linhas cron, automações sem código) em uma planilha de regras neutra, verifica loops de autoativação, cadeias desprotegidas, limites ausentes e duplicação, e depois reproduz eventos reais ou gravados para mostrar cada execução que teria sido iniciada, o que foi mesclado, ignorado, enfileirado ou descartado, e o custo por execução.

O que é trigger-rehearsal?

O Trigger Rehearsal é uma ferramenta de simulação e validação de regras de gatilho para agentes de IA orientados por eventos ou em segundo plano. Ele permite que desenvolvedores e engenheiros testem o comportamento de suas regras de ativação antes de colocá-las em produção, evitando loops infinitos, estouro de orçamento, cadeias descontroladas e ações não autorizadas. A ferramenta suporta múltiplos formatos de regras, como arquivos de hubs de agentes, rotinas, blocos 'on:' de CI, linhas cron e automações sem código, traduzindo todos para um formato neutro em `rules.json`. Durante a simulação, ele realiza lint para identificar problemas (HOLD, REVIEW, TRIM) e reproduz eventos reais ou sintéticos para gerar um relatório detalhado com o número de execuções, eventos processados, enfileirados, descartados e o custo estimado. O Trigger Rehearsal é ideal para ser usado antes de ativar qualquer regra que permita que um agente inicie trabalho automaticamente, ao adicionar novas regras a um conjunto existente, ou quando um agente em segundo plano executa com mais ou menos frequência do que o esperado. A ferramenta é agnóstica de plataforma e pode ser integrada a fluxos de CI para bloquear mudanças de configuração que introduzam loops ou estouro de orçamento.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/fangdididi/trigger-rehearsal/tree/HEAD

Installed? Explore more Programação e Desenvolvimento skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Ensaio de Gatilho

O que é isso

Um agente que se ativa sozinho em eventos é tão seguro quanto suas regras de gatilho. O agente em si pode ser cuidadoso e ainda assim queimar o orçamento do dia, porque o problema geralmente está um nível acima:

  • uma regra reage a um evento que seu próprio trabalho produz, então ela dispara de novo e de novo;
  • duas regras se alimentam mutuamente através de um segundo sistema (o agente comenta, o comentário sincroniza, a sincronização dispara um webhook);
  • uma fonte barulhenta envia dez edições em dois minutos e cada uma inicia uma nova execução;
  • uma linha cron pensada como "verificar de vez em quando" dispara 288 vezes por dia;
  • duas regras tratam o mesmo evento e fazem o trabalho duas vezes;
  • uma regra que reembolsa, deleta ou envia mensagens para pessoas é executada sem perguntar a ninguém.

Nenhum desses problemas aparece quando você testa o agente em um exemplo isolado. Eles aparecem quando o tráfego real chega. O Ensaio de Gatilho faz o tráfego real chegar antes, no papel: você escreve as regras em um formato neutro, reproduz um dia ou uma semana de eventos através delas e lê a linha do tempo antes que qualquer coisa seja ativada.

Quando usar

  • Antes de ativar qualquer regra que permita a um agente iniciar trabalho sem que uma pessoa digite um prompt.
  • Ao adicionar uma regra a um conjunto existente (uma nova regra pode fechar um loop que estava aberto antes).
  • Quando um agente em segundo plano executou com muito mais ou muito menos frequência do que o esperado.
  • Ao escolher janelas de debounce, limites de paralelismo e limites diários, e você quer números em vez de suposições.
  • Quando um revisor pergunta "o que acontece se este repositório receber 50 issues em uma hora?"

Não serve para: verificar o que o agente faz dentro de uma execução (isso é uma questão de prompt ou habilidade), ou testar a carga da própria fonte de eventos.

A planilha de regras

Tudo é traduzido para rules.json. Mantenha a tradução honesta: uma regra da planilha por regra real e escreva as proteções que realmente existem, não aquelas que você pretende adicionar.

{
  "tz": "America/Sao_Paulo",
  "run_s": 180,
  "external_sources": ["github"],
  "budget": {"runs_per_day": 40, "cost_per_run": 0.15, "cost_per_day": 6},
  "rules": [
    {
      "name": "triagem-nova-issue",
      "on": {"source": "github", "types": ["issues.opened", "issues.edited"]},
      "where": {"repo": "meu/app"},
      "key": "subject",
      "debounce_s": 300,
      "parallel": 1,
      "max_per_day": 20,
      "unless_actor": ["meu-bot"],
      "unless_label": "triado",
      "emits": [{"source": "github", "types": ["issues.labeled"], "actor": "meu-bot", "labels": ["triado"]}],
      "sensitive": [],
      "asks": false
    },
    {"name": "resumo-matinal", "on": {"cron": "0 9 * * 1-5"}, "max_per_day": 1}
  ]
}
CampoSignificado
on.source + on.typesQuais eventos iniciam a regra. Deixe types de fora para corresponder a qualquer tipo daquela fonte.
on.cronUma linha cron de cinco campos no fuso horário da planilha. Uma regra tem source ou cron.
whereCampos do evento que devem ser iguais a um valor (ou estar em uma lista).
keyCampo do evento que nomeia o assunto (número da issue, ID do ticket, URL). Usado para mesclar repetições.
debounce_sAguarde este tempo após o último evento para um assunto e depois execute uma vez.
parallelQuantas execuções desta regra podem estar ativas ao mesmo tempo. Execuções extras aguardam.
max_per_dayLimite máximo por dia local. Execuções extras são descartadas.
run_sDuração típica da execução, usado para fila. Recai para o valor da planilha, depois para 120.
unless_actor, unless_labelProteções: ignore eventos feitos por esses atores, ou que carregam este rótulo.
emitsEventos que a execução em si produz (comentários, rótulos, mudanças de status, eventos de acompanhamento). Inclua o ator e os rótulos que carregará.
sensitive + asksAções que precisam de uma pessoa (deletar, gastar, reiniciar, enviar). asks: true significa que a execução para e pergunta primeiro.
external_sourcesFontes alimentadas pelo mundo exterior. Qualquer outra coisa deve ser emitida por uma regra.
budgetOpcional: execuções por dia, custo por execução e custo por dia usados para o veredito.

Passo a passo

  1. Colete as regras reais. Leia a configuração real, não a descrição dela. Arquivos de regras de hubs de agentes, rotinas salvas, blocos on: de workflows de CI, linhas crontab, telas de automação sem código. Anote qualquer coisa que escreva de volta para uma fonte que outra regra observa.
  2. Traduza para rules.json. Comece com python3 scripts/rehearse.py new rehearsal/. Para cada regra, faça três perguntas e preencha os campos: o que a ativa, o que uma execução escreve de volta, e o que a impede de ativar com suas próprias escritas. Se a resposta para a terceira for "nada", deixe a proteção de fora. O ensaio serve para pegar isso.
  3. Lint. python3 scripts/rehearse.py lint rehearsal/rules.json. Corrija todos os HOLD antes de reproduzir; itens REVIEW podem esperar pelos números.
  4. Colete eventos. Melhor: exporte um dia real movimentado da fonte (log de entrega de webhook, linha do tempo de issues, log de auditoria de helpdesk) para events.jsonl, um objeto JSON por linha com pelo menos t, source, type, mais os campos que seu key e where usam. Se não houver histórico, escreva uma pequena rajada sintética de propósito: dez edições em três minutos, dois assuntos ao mesmo tempo, um evento feito pelo seu próprio bot.
  5. Reproduza em dias inteiros. python3 scripts/rehearse.py replay rehearsal/rules.json rehearsal/events.jsonl --from 2026-11-02T00:00:00Z --to 2026-11-03T00:00:00Z --md rehearsal/report.md. Passe --from/--to para que os números por dia não sejam inflados por uma janela curta.
  6. Leia a linha do tempo, não apenas o veredito. Procure por execuções no mesmo assunto com minutos de diferença (debounce ausente ou curto), cadeias com profundidade crescente (loops), longas esperas (paralelismo muito baixo), descartes (limite muito baixo para trabalho real, ou um sinal de que a regra dispara em ruído).
  7. Ajuste e repita. Mude um parâmetro de cada vez e reproduza os mesmos eventos, para que a diferença seja claramente dessa mudança.
  8. Decida. ARME apenas quando a última reprodução for ARM em um dia realista. Mantenha o rules.json final, o arquivo de eventos e report.md juntos como o registro do motivo pelo qual as regras foram ativadas.

Vereditos

  • ARM: nenhum achado HOLD ou REVIEW. Seguro ativar como está.
  • TRIM: algo desperdiça execuções ou pode pular trabalho (sem key, sem limite, sobreposição, limite descartou eventos reais, perto do orçamento). Ative apenas após cortar, ou com um motivo por escrito.
  • HOLD: não ative. Auto-loop, ciclo desprotegido, uma cadeia que passou da profundidade 5, uma ação sensível sem perguntar, acima do orçamento, ou uma linha cron quebrada.

O código de saída segue o veredito (0, 1, 2; 3 significa entrada inválida), para que um ensaio possa bloquear uma mudança de configuração no CI.

Exemplo

Uma equipe de suporte quer um agente para responder tickets de helpdesk. A planilha deles (em examples/loopy/) tem uma regra de resposta que posta uma réplica, que atualiza o ticket, que corresponde à mesma regra. Uma reprodução de um dia comum dá:

HOLD   self-loop            responder-ticket: a própria saída da regra corresponde ao seu próprio gatilho sem proteção unless_actor/unless_label
HOLD   runaway              responder-ticket: cadeia continuou disparando além da profundidade 5 (3 cortes)
HOLD   sensitive-unasked    verificar-reembolso: declara ações sensíveis ['reembolso'] mas 'asks' não é true
HOLD   over-runs-budget     -: 100.0/dia contra um orçamento de 30/dia
REVIEW cron-tight           verificar-caixa: até 720 disparos/dia
VERDICT HOLD

Três atualizações de ticket se transformaram em 18 execuções de resposta. A correção é pequena: adicione "unless_actor": ["bot-suporte"] à regra de resposta, defina "asks": true na regra de reembolso e substitua a verificação de dois minutos por um script que emite inbox.changed apenas quando a caixa de entrada realmente mudou (veja examples/loopy/rules.fixed.json). A próxima reprodução do mesmo dia cai de 100 execuções para 4 e o veredito vai para TRIM. O único achado restante é que responder e verificar reembolso veem um ticket de reembolso, o que é intencional aqui, então é aceito com um motivo de uma linha por escrito ao lado do relatório.

Dicas

  • A melhor proteção contra loop único é uma condição que se torna falsa após a execução: um rótulo que a execução adiciona e a regra exclui, ou um status que a regra não corresponde mais.
  • Loops entre sistemas são os mais fáceis de perder. Se o agente escreve no sistema A e o sistema A sincroniza com B, liste o evento sincronizado em emits com o ator que ele mostrará.
  • Debounce adiciona atraso por design. Escolha a janela com base em quanto tempo uma pessoa leva para terminar uma rajada de edições e mantenha-a curta onde alguém espera por uma resposta.
  • Debounce não é deduplicação de ações. Para qualquer coisa irreversível, a execução em si ainda deve verificar "já foi feito?" antes de agir.
  • Um limite diário é um fusível, não um plano. Se a reprodução de um dia normal o atingir, a regra é muito ampla.
  • Polling a cada poucos minutos geralmente é mais barato como um pequeno script que compara o estado e emite um evento na mudança; o agente só acorda quando há algo novo.
  • Execute novamente o ensaio sempre que uma regra for adicionada. A maioria dos loops é criada pela segunda regra, não pela primeira.

Habilidades Relacionadas