Fiz a IA assinar um contrato de trabalho
5 min de leitura #laravel #ia #claude-code
Codar com IA deixou de ser o problema. O problema virou fazer ela seguir os meus padrões.
Resolvi isso num plugin do Claude Code, o astro. Ele é uma esteira do contrato ao Pull Request, mas o que importa de verdade não são os comandos. São os templates que a IA é obrigada a seguir, e as regras por trás de cada um. É sobre isso que eu quero falar.
O que o setup organiza
O astro:setup é a fase 0, e faz mais do que gravar regra. Ele detecta a stack, grava o contrato no CLAUDE.md (as barreiras e os padrões de escrita) e, quando o projeto é Laravel, organiza o terreno antes de qualquer código:
- Puxa a minha arquitetura do meu Git. Eu mantenho num repositório, o
bellinivitor/laravel-architecture, umAGENTS.mdcom a arquitetura domain-driven que eu sigo. O setup baixa esse doc pradocs/architecture/do projeto, pra ficar versionado e disponível offline, e registra noCLAUDE.mdque é pra seguir ele. - Confirma o autoload. Garante que o namespace
Domain\está mapeado no PSR-4 docomposer.json. - Cria um
AGENTS.mdpor domínio e a estrutura de exceptions tipadas de domínio.
Com isso a IA já começa sabendo onde cada coisa vai, em vez de inventar a estrutura.
O gate (e o appzinho das regras)
Prompt é prompt. A IA lê o contrato, concorda, e meia hora depois sugere um migrate:fresh "só pra limpar o banco".
Por isso tem um gate: um hook do Claude Code que roda antes de cada comando no terminal, lê o texto e barra a execução se bater num padrão proibido. migrate:fresh, rm -rf, git push --force, truncate, composer update, nenhum passa. O prompt orienta, o código garante.
Só que eu não queria editar regra na unha, num JSON escondido. Então fiz um appzinho. É o ai-gate/: uma mini aplicação em Python puro, sem nenhuma dependência, que o setup instala no projeto. As regras ficam num SQLite, e você edita numa interface no navegador.
Rode astro:gate. Ele sobe um servidor local, abre a tela, e ali você liga, desliga, edita ou adiciona regra (regex ou texto literal). Clica em Gerar gate e pronto.
O detalhe que eu gosto: o gate gerado é autossuficiente. As regras ficam embutidas no arquivo, então ele não depende do SQLite pra rodar. Dá pra copiar e usar como CLI na VM ou no CI:
python3 astro_gate.py "$CMD" && eval "$CMD"
O SQLite é a fonte da verdade. O script é só um artefato gerado dali.
flowchart LR
CMD([Comando]) --> MODE{Como chega?}
MODE -->|Claude Code| HOOK[Hook PreToolUse]
MODE -->|VM / CI| CLI[CLI: astro_gate.py CMD]
HOOK --> GATE
CLI --> GATE
DB[(rules.db · SQLite)] -->|Gerar gate| GATE
GATE[astro_gate.py<br/>lê o comando] --> CHECK{Padrão<br/>proibido?}
CHECK -->|Sim| BLOCK["🚫 Bloqueia<br/>comando NÃO roda"]
CHECK -->|Não| ALLOW["✅ Libera<br/>comando roda"]
style BLOCK fill:#fde2e1,stroke:#b42318
style ALLOW fill:#e3f5e8,stroke:#1f7a3f
style GATE fill:#edebfb,stroke:#4738c8
O commit
Nada de mensagem genérica. O astro:commit escreve sempre assim:
<TIPO>: <Título curto e objetivo>
- <Alteração 1>
- <Alteração 2>
A regra que faz diferença: tudo no particípio passado, porque o commit descreve algo que já foi feito. "Adicionado cadastro de estoque", não "Adicionar cadastro". E um commit por mudança lógica. Se a descrição pede um "e", provavelmente são dois commits.
O Pull Request
O PR não repete a task. Ele diz ao revisor o que olhar no diff e como validar:
## O que foi feito
- <mudança técnica: arquivo, classe, endpoint, tabela>
## Impacto
<migration, contrato de API, job, cache; ou "nada além do escopo">
## Como testar
1. <preparo e passo a passo>
## Pontos de atenção
<o que olhar com cuidado, dívida deixada; ou "nenhuma">
A regra do Impacto aqui é a que mais me incomodava: nada de número que você não mediu. O texto saía sempre exagerado, com "pode pesar o banco" e cifras chutadas. Então o PR é simples, pro PO bater o olho e entender, sem inventar magnitude.
A entrega
Esse é o meu favorito. O astro:answer gera o texto que vai pro QA e pra quem sobe, num arquivo local (markdown colado do terminal quebra tudo):
### O que foi feito
### Impacto
- Dados: +X MB em 30 dias (N linhas/dia × Y KB)
- Banco: +N queries por request, índice novo
- Performance: endpoint Xms antes, Yms depois
### Como testar
### Deploy
### O que ficou de fora
### Observações
E aqui a regra se inverte em relação ao PR: na entrega, número vale mais que adjetivo. "Pode pesar o banco" não dá pra avaliar. "+2,4 GB em 30 dias" dá. Ordem de grandeza basta, o que importa é a diferença entre 2 MB e 2 GB.
E se não der pra medir na hora? Escreve a conta e a suposição: "estimo 40k linhas/dia assumindo o volume de pedidos de hoje". Suposição escrita alguém corrige. Número ausente ninguém questiona.
Um AGENTS.md por domínio
Esse resolve um problema chato: a IA mexer num domínio sem entender o que ele faz. Então todo app/Domain/{Dominio}/ ganha um AGENTS.md com um template fixo:
## Propósito e fronteira
## Linguagem (glossário)
## Modelos principais
## Estados e transições
## Regras de negócio
## Ações (casos de uso)
## Contratos expostos
## Dependências
## Exceptions
## Pontos de atenção
A regra: curto e de alto sinal. Seção vazia some, e atualiza quando o comportamento muda. Doc desatualizada engana mais que ausência.
A decisão que não é template: o plano é efêmero
Tem uma coisa que eu fiz questão de não virar arquivo. O plano do astro:plan vive na lista de tarefas da sessão, não em pastas de .md versionadas. Eu não queria 200 arquivos de planejamento poluindo o repositório. O que fica versionado é código, não cerimônia.
O código está aberto
Instala direto do GitHub:
/plugin marketplace add bellinivitor/astro
/plugin install astro@astro
O código está aberto no GitHub: https://github.com/bellinivitor/astro
E sim, 100% feito com o Claude Code. Eu descrevia, ele escrevia, e o gate segurava a mão dele quando precisava.