stamatios
← Voltar ao feed
Apito de árbitro ao lado de robô correndo em pista de código, metáfora do linter rigoroso para agentes
Agentes · Dev & Engenharia

Ultracite propõe linter rápido e com regras estritas para agentes de código

resumo de ~3 min

Do lint ao ciclo do agente

Em 1978, Stephen C. Johnson criou o lint, uma ferramenta que verificava código C com mais rigor que o compilador. Ele manteve as duas coisas separadas de propósito: o compilador precisava ser rápido, enquanto o lint podia demorar para encontrar código válido, mas provavelmente errado. Johnson aceitava avisos apenas na proporção dos bugs reais que encontravam, por isso as verificações mais exigentes ficavam atrás de uma opção que era preciso pedir.

Segundo o autor, por cerca de cinquenta anos essas limitações vieram das pessoas: ninguém espera uma verificação lenta nem lê um relatório barulhento. Assim, o lint foi sendo adiado ou ignorado, e as configurações se ajustaram ao que as pessoas toleravam. Em 2022, Hayden Bleasel usava uma configuração de ESLint de 642 linhas. Ela se dizia estrita, mas desligava complexity e sort-keys. Ele não considerava essas regras erradas; apenas não queria corrigi-las à mão.

O ciclo agentic

Agentes não têm esses limites. Eles trabalham em turnos: editam arquivos e, antes de devolver o resultado, rodam lint, formatador, verificador de tipos e, muitas vezes, testes. Se algo falha, corrigem e executam de novo. Para o autor, nesse fluxo o lint não pode ser adiado, pois o agente roda as verificações a cada turno e lê todas as linhas impressas. Elas são também o único retorno que o agente recebe antes de uma pessoa ver o código.

Por isso, Bleasel acredita que o ciclo é hoje um dos melhores lugares para investir esforço em uma base de código. As verificações precisariam ser rápidas o bastante para rodar a cada turno, rigorosas o bastante para valer a pena e difíceis de burlar. É esse o objetivo do Ultracite, que começou como aquela configuração pessoal. Segundo o autor, os dois maiores saltos de downloads vieram quando a ferramenta foi reorientada para agentes, nas versões 5 e 7, e no último mês ela foi baixada cerca de 4 milhões de vezes.

Velocidade

Johnson podia deixar o lint demorar porque ele ficava fora do compilador. No ciclo, a verificação roda a cada turno e o agente espera por ela, então um linter lento deixa o agente lento. Ao entrar na OpenAI, Bleasel migrou alguns projetos para Oxlint, Oxfmt e Ultracite. O tempo de lint e formatação caiu de cerca de 2 minutos para cerca de 3 segundos, o que, segundo ele, devolve cerca de dois minutos a cada turno do Codex.

Por esse motivo, o Ultracite recomenda Oxlint e Oxfmt no lugar de ESLint e Prettier. Seu hook para agentes executa ultracite fix apenas no arquivo alterado, logo após cada edição, para que o agente não gaste um turno com formatação.

Rigor sem ruído

O outro limite de Johnson era o ruído, e agentes também mudam isso. Um agente não deixa de confiar no linter após alguns alarmes falsos: lê o quadragésimo aviso com a mesma atenção que o primeiro. Uma regra que levaria uma pessoa a desligá-la custa ao agente apenas alguns segundos. Assim, regras antes desligadas podem voltar. Complexity e sort-keys são erros no Ultracite atualmente, assim como no-warning-comments, que proíbe TODO, porque agentes costumam deixar // TODO: implement no lugar da parte difícil.

Agentes são não determinísticos, e linters não. Quanto mais da saída do agente puder ser verificada por regra, menos ela precisará ser lida com atenção. O Ultracite também grava seus padrões em AGENTS.md, CLAUDE.md e outros arquivos de regras, para que o agente os conheça antes de escrever código.

Difícil de burlar

Uma verificação rigorosa só ajuda se o agente corrigir o problema em vez de escondê-lo. Diante de um erro de tipo que não consegue resolver, o agente tende a recorrer a as any ou @ts-ignore. Por isso, o Ultracite ativa strictNullChecks e torna ambos erros. Há ainda um preset opcional, baseado no plugin anti-slop de Dillon Mulroy, que exige um comentário justificando por que cada asserção de tipo é segura. Bleasel diz que nunca pediria isso a uma pessoa, mas um agente faz sem dificuldade.

Na segurança, o Ultracite marca casos óbvios, como eval e dangerouslySetInnerHTML, e oferece um preset opcional para o gdp-ts, de Guillermo Rauch. Esse pacote se baseia em Ghosts of Departed Proofs, artigo de Matt Noonan de 2018 sobre codificar pré-condições no sistema de tipos. Funções sensíveis exigem prova de que a checagem de autorização ocorreu, e só um módulo confiável pode criar essas provas. Se o agente pular a checagem, o código não passa na verificação de tipos, e as regras impedem que ele simule a prova com uma asserção.

Limites

Nada disso significa ativar todas as regras. Cada aviso ocupa contexto, e o agente segue uma regra ruim tão fielmente quanto uma boa. Por isso, max-lines e max-params continuam desligadas, pois um limite arbitrário piora o código, qualquer que seja o autor. Na versão 7, a regra de complexidade foi um pouco afrouxada após sinalizar código razoável demais. Além disso, as verificações só cobrem o que pode ser verificado: não dizem se o agente construiu a coisa certa, e isso continua a cargo da revisão final.

Bleasel acredita que a maioria das bases de código terá verificações que pareceriam extremas há alguns anos, e que poucas pessoas notarão, porque não são elas que leem a saída. Ao lembrar que, em 1978, o lint ficava fora do ciclo e as verificações mais exigentes dependiam da opção -h, ele conclui que hoje a ferramenta roda a cada turno. Sua recomendação é torná-la rápida e deixar -h ativado.