learnaiwithrafa
ClaudeWorkflows

Pra parar de vigiar o Claude, dê um teste que falha

Autonomia não é problema de permissão, é problema de verificação. O Claude já consegue rodar sozinho — o que falta é uma checagem que ele não consiga contornar com conversa. Aqui estão as três que dá pra montar hoje.

7 min de leitura3 fontes
  • #claude-code
  • #testing
  • #hooks

Todo mundo que pergunta "como eu deixo o Claude rodar sem eu olhar" está fazendo a pergunta errada. Você já consegue — o modo automático aprova as chamadas de ferramenta, e /loop e cron rodam a noite inteira. O motivo de você ainda ficar pairando sobre o terminal não é permissão. É que você não tem como saber se o trabalho realmente terminou, então lê cada diff na mão. Isso não é supervisão. Isso é você virar a suíte de testes.

A saída é parar de ser a checagem. Cada hora de trabalho autônomo que você quer tem que ser paga com uma verificação que roda sem você — e existem exatamente três lugares pra colocar uma.

A sacada que muda tudo de lugar: /goal

O /goal define uma condição de conclusão e o Claude continua tomando turnos até ela ser satisfeita. Depois de cada turno, um modelo pequeno e rápido — Haiku por padrão — lê a conversa e decide se a condição vale. Um "não" volta com um motivo, e esse motivo vira orientação pro turno seguinte.

/goal all tests in test/auth pass and the lint step is clean

Agora a restrição que ensina a escrever toda condição que você vai escrever na vida: o avaliador não roda comando e não lê arquivo. Ele só consegue julgar o que o Claude já trouxe pra conversa.

Pare um segundo nisso. Significa que uma condição do tipo "o código está bem estruturado" não vale nada — não tem nada no histórico que prove isso. Mas "pnpm test auth sai com 0" funciona perfeitamente, porque o Claude é obrigado a rodar o comando e a saída cai no histórico, onde o avaliador consegue ler. A condição verificável não é só uma boa prática: é o único tipo que funciona.

Então uma condição que presta tem três partes: um estado final mensurável, o comando que prova aquilo e o que não pode mudar no caminho.

/goal every call site of the old session API is migrated.
Done means: `pnpm typecheck` exits 0, `pnpm test auth` exits 0,
no file outside src/auth/ is modified, or stop after 20 turns.

Aquela última cláusula não é enfeite. A condição pode ter até 4.000 caracteres, e um goal segue rodando até ser satisfeito ou você limpar — o limite de turnos é o seu disjuntor.

A camada que não negocia: hooks

O /goal é um modelo julgando um histórico. Útil, mas é um modelo. Quando você precisa de uma checagem que vale independentemente do que o Claude decidir, você precisa de um hook — e a doc é explícita: hooks executam como comando de shell em eventos fixos do ciclo de vida, não importa a conclusão do modelo.

Um hook de PostToolUse que roda depois de cada edição e devolve as falhas:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/check.sh"
          }
        ]
      }
    ]
  }
}
#!/bin/bash
input=$(cat)
file_path=$(jq -r '.tool_input.file_path' <<<"$input")

if ! npx eslint "$file_path"; then
  jq -n '{decision: "block", reason: "Lint falhou. Corrija antes de continuar."}'
  exit 0
fi
exit 0

O formato {"decision": "block", "reason": "..."} é o que vale aprender. Seu reason chega no Claude como retorno, então ele se corrige em vez de parar. Você transformou o seu linter em parte do loop do agente, em vez de uma coisa que você roda depois e fica irritado.

Dois outros que vale conhecer:

  • PreToolUse bloqueia antes da execução — saia com código 2 e o seu stderr vira o motivo do bloqueio, ou devolva permissionDecision: "deny" em JSON. É aqui que mora aquela regra que você não consegue expressar como glob.
  • Stop dispara quando o Claude acha que terminou. Saia com 2 e ele não terminou. Esse é o seu portão de "você rodou os testes de verdade?", e é o hook de maior alavancagem do sistema todo.

Aliás, o /goal é um hook de Stop baseado em prompt com escopo de sessão, por baixo do capô. O que já te diz onde está o poder real: um hook de Stop no seu arquivo de configuração vale pra toda sessão daquele escopo, e pode rodar um script pra fazer uma checagem determinística em vez de perguntar pra um modelo.

A camada pro trabalho que passa da sessão

O /loop re-executa um prompt num intervalo — /loop 5m check if the deployment finished. Sem o intervalo, o Claude escolhe o próprio atraso a cada iteração com base no que viu, entre um minuto e uma hora.

Conheça os limites antes de depender disso:

  • As tarefas só disparam enquanto o Claude Code está rodando e ocioso. Fecha o terminal, para tudo.
  • Tarefa recorrente expira 7 dias depois de criada — um limite deliberado pra quanto tempo um loop esquecido pode rodar.
  • Não tem recuperação de disparo perdido. Um disparo que passou acontece uma vez, não uma vez por intervalo perdido.
  • Conversa nova limpa tudo; --resume restaura o que não expirou.

Pra qualquer coisa que precise sobreviver ao seu notebook fechando, essa é a ferramenta errada — use Routines na infraestrutura da Anthropic, uma tarefa agendada no Desktop, ou um schedule no GitHub Actions.

Escolha pelo que deve iniciar o próximo turno

O modelo mental limpo, que eu levei tempo demais pra montar:

  • /goal — o próximo turno começa quando o anterior termina; para quando um modelo confirma a sua condição.
  • /loop — o próximo turno começa quando passa um intervalo de tempo; para quando você para ou passam sete dias.
  • hook de Stop — o próximo turno começa quando o anterior termina; para quando o seu script disser.

Acompanhando um build? /loop. Moendo uma migração até ficar verde? /goal. Impondo "os testes passam antes de você me dizer que acabou" em toda sessão, pra sempre? hook de Stop.

A conclusão desconfortável

Se o seu repositório não tem teste, você não pode ter agente autônomo. Não é que "funciona pior" — falta o mecanismo. O /goal não tem o que avaliar, o seu hook não tem o que rodar, e você volta a ler diff na mão.

O que muda completamente a conversa sobre cobertura de teste. Aqui, ela deixou de ser sobre pegar regressão e virou a interface que eu uso pra delegar. O time que eu lidero escreve teste mais rápido hoje do que antes do Claude Code, e não por um motivo nobre: módulo sem teste é módulo que ninguém consegue entregar pra um agente, então ele fica lento — e todo mundo percebe.

Faça isso hoje

Pegue uma tarefa que você normalmente supervisionaria. Escreva a condição do /goal primeiro, antes de qualquer código — com um comando real e um exit code dentro. Se você não conseguir escrever essa linha, você acabou de achar o teste que falta, e escrever ele é o trabalho de verdade. Depois rode o goal com o modo automático ligado e vá fazer outra coisa.

Fontes