a skill que escrevi pra IA parar de complicar meu código
um SKILL.md com prioridade de regras, escada de solução, escopo mínimo (sem global à toa) e quality gate, pra agente de código entregar a menor mudança correta
10 minver no github
atualizado em 2026-10-05: reescrevi a skill (de 44 seções pra uma versão bem menor) depois de compará-la com o ponytail. veja "o que mudou / o que aprendi com o ponytail" mais abaixo.
atualizado em 2026-10-05 (de novo): a skill virou clean-code-ai: juntei com um rascunho meu mais antigo, também chamado clean-code-ai, e ela substitui a pragmatic-code. veja "virou clean-code-ai" mais abaixo.
tl;dr#
agente de código tem um vício: pedir uma coisa pequena e receber de volta uma camada nova, uma interface com uma implementação só, uma dependência e um catch {} pra "garantir". escrevi um SKILL.md chamado clean-code-ai (antes pragmatic-code) que diz pro agente como analisar, gerar, corrigir, refatorar e revisar código com um objetivo só: entregar a menor solução correta e segura, no menor escopo que funciona, seguindo as convenções do projeto. o arquivo completo está em SKILL.md. aqui eu resumo as partes que mais importam. é uma versão em andamento: eu continuo mexendo nela.
o problema#
código gerado por IA costuma funcionar e ainda assim ser ruim de manter. os sintomas que mais me incomodaram:
- abstração sem necessidade: repository, factory, service, tudo passando chamada pra frente sem fazer nada;
- dependência nova pra coisa que a stdlib ou o framework já resolvem;
- lint e TypeScript silenciados (
@ts-ignore,eslint-disable) só pra passar; try/catchvazio escondendo erro;- código comentado e TODO inútil largados no diff;
- mudança que quebra contrato de outra parte do sistema sem ninguém avisar;
- estilo e estado indo parar no escopo global só pra "reaproveitar" (esse eu só percebi usando o ponytail, mais abaixo).
como sou dev front-end júnior e uso IA pra aprender, isso pesa em dobro: se eu não percebo o excesso, ele vira o "jeito certo" na minha cabeça. então escrevi as regras que eu queria que o agente seguisse, e que eu mesmo quero aprender a seguir.
a ideia central#
antes de escrever código, o agente precisa entender o problema, ler os arquivos relevantes, achar quem consome aquilo e checar contratos. só depois escolhe a menor solução. e explica de forma proporcional: pra mudança trivial, uma frase basta.
Objetivo: a menor solução correta, segura e compatível com o projeto, no menor escopo que funciona e seguindo as convenções que já existem.
repara que "menor" vem junto de "correta" e "segura". o menor diff só vale depois de entender o fluxo inteiro.
o que eu acho mais importante#
1. prioridade de regras#
quando duas regras brigam, tem ordem pra decidir: segurança, correção e requisitos explícitos, contratos e integridade de dados, convenções do projeto, simplicidade, legibilidade, performance (só com necessidade concreta), e por último abstração e gosto. simplicidade fica no meio de propósito. e tem uma frase que existe pra evitar o pior efeito colateral de "faça simples":
Simplicidade nunca justifica remover autenticação, autorização, validação, integridade, tratamento de erro, acessibilidade básica ou requisito explícito.
sem isso, "simplifica" vira "tira a validação".
2. escada de solução#
antes de adicionar código, o agente desce essa escada e para no primeiro degrau que resolve direito:
precisa existir? → reusar → stdlib → API nativa → dependência já instalada → poucas linhas → abstração → dependência nova
"uma dependência instalada não é uma dependência obrigatória". estar no package.json não é motivo pra usar.
3. escopo e localidade (minimal não é centralizado)#
esse é o degrau novo, e o mais importante da versão 2. regra: reusar não significa jogar no global. coloca no menor escopo que funciona e segue como o projeto já faz.
- estilo: usa a convenção que já existe (Tailwind, CSS Modules, estilo colocalizado). valor de uso único fica local. só vira token global quando é uma decisão de design compartilhada, usada em 2+ lugares, e o projeto já tem sistema de tokens.
- estado: fica no componente, sobe só até o pai comum mais próximo. context, store ou singleton só quando o estado é de fato compartilhado.
- helpers e constantes: do lado de quem usa. vão pra
utils/quando aparece o segundo consumidor de verdade.
- /* globals.css */
- :root { --contact-card-gap: 14px; }
- .contact-card { gap: var(--contact-card-gap); }
+ <div className="flex gap-3.5"> {/* um uso, projeto usa Tailwind */}
4. não silenciar ferramenta nem erro#
@ts-ignore, eslint-disable e parecidos não entram só pra fazer a implementação passar. o certo é corrigir a causa. suspensão legítima existe, mas tem que ser mínima e explicada. mesma lógica pra catch {}: um erro é tratado, convertido, propagado ou ignorado de propósito, com comentário dizendo o porquê.
5. breaking change tem que ser dito#
se a única solução correta quebra um contrato existente (função exportada, endpoint, schema, props, tipo), o agente não aplica em silêncio. ele aponta o contrato afetado, explica por que é necessário, avalia quem consome e, se der, propõe um caminho de transição. quebrar pode ser a decisão certa, mas tem que ser explícita.
6. quando minimal está errado#
seção nova, nascida das falhas de skills "minimalistas": apagar código que parece morto mas é usado por string ou config; pular validação, erro ou acessibilidade pra encurtar diff; recusar um teste que a lógica precisa; espremer código legível num one-liner esperto; editar arquivo gerado; apagar comentário que explica o porquê; ignorar i18n. a skill manda fazer mais, não menos, nesses casos.
7. quality gate#
uma checklist curta antes de entregar: requisito atendido sem extra, causa raiz e contratos, escopo mínimo (estilo, estado, helpers), abstração e global realmente necessários, fronteiras de confiança e erros intactos, nada silenciado, acessibilidade e i18n sem regressão, e os comandos reais do projeto rodados (sem inventar script).
o que mudou / o que aprendi com o ponytail#
o ponytail é uma skill popular com a mesma ideia (código mínimo). instalei, usei e li o SKILL.md inteiro. ele me ensinou bastante sobre como escrever uma skill que o agente segue de verdade:
o que eu peguei dele
- é curto: dá pra ler em 2 minutos, e o agente de fato segue. a minha tinha 44 seções que se repetiam;
descriptioncom gatilhos claros ("be lazy", "yagni", reclamação de over-engineering) e com o "quando não usar";- formato de resposta fechado: código primeiro, no máximo três linhas,
skipped: X, add when Y; - níveis de intensidade (lite, full, ultra) e exemplos curtos de cada um;
- comentário
ponytail:marcando o teto de uma simplificação, e a regra de deixar um check executável pra lógica não trivial.
o que eu quis manter da minha
- prioridade explícita: segurança, correção e contratos acima de simplicidade;
- fronteiras de confiança, autorização, integridade e concorrência de verdade (o ponytail só cita validação de passagem);
- breaking change tratado como decisão explícita, com migração;
- não silenciar ferramenta, quality gate, arquivo gerado.
onde eu senti falta de algo
- usando o ponytail no meu dia a dia, senti o "reutilizar" puxar pro global: o agente cria variável CSS em
:root, token, classe em stylesheet global, store ou singleton pra valor de uso único, porque "centralizar" parece menos código. na prática vira acoplamento e diff maior. também não diz nada sobre acessibilidade de verdade, i18n, estilo do projeto ou apagar comentário que explica o porquê, e "uma linha antes de cinquenta" incentiva one-liner ilegível; - na minha versão antiga, o problema era outro: longa demais, seções repetidas, pouco exemplo,
descriptiongenérica que dispara pouco, e nenhuma palavra sobre escopo.
o que eu fiz
- cortei de ~2500 pra ~1400 palavras consolidando as seções repetidas;
descriptionnova no estilo ponytail (gatilhos, quando usar, quando não usar);- adicionei "escopo e localidade" e "quando minimal está errado" (precauções), exemplos curtos com antes/depois, seção de frontend (React, Next.js, Tailwind, i18n, acessibilidade) e formato de resposta curto;
- não copiei os níveis de intensidade. pra quem usa no dia a dia eu não vi ganho real: pedir "mais enxuto" já resolve, e três modos viram mais uma coisa pro agente decidir. se eu sentir falta, volto.
a lição que eu levo: minimal não é sinônimo de centralizado nem de "o menor número de caracteres". é o menor mudança correta, no menor escopo, no estilo que o projeto já usa.
virou clean-code-ai#
atualização de 2026-10-05: juntei a skill com um rascunho meu mais antigo, também chamado clean-code-ai, e o resultado se chama clean-code-ai e substitui a pragmatic-code. o arquivo SKILL.md agora é a versão em português; em inglês fica em SKILL.en.md. o que a versão nova tem a mais que a pragmatic-code:
- os níveis voltaram: lite, full e ultra, com
/clean-code-ai offpra desligar. antes eu tinha escrito que não copiei os níveis; com essa junção eles voltaram, já que o rascunho antigo tinha; - a escada ganhou "remover código" como degrau, e abstração só com 2+ usos reais hoje;
- prioridade de regras: contratos existentes e integridade dos dados viraram itens separados (eram um só), e "gosto pessoal de estilo e abstração" fica por último;
- exemplo de estado no lugar errado:
useState+useEffectpra um valor que dá pra calcular durante o render; - critério de parada: se o diff passa de ~50 linhas, cria arquivo novo, abstração, global ou dependência, a skill pede uma frase de justificativa concreta. se eu pedi a feature explicitamente, o arquivo novo já está justificado e ela segue sem travar;
- arquivo regenerado por ferramenta (dicionário de i18n, bloco que o
next devescreve): não reverte à mão, commita junto ou deixa a ferramenta cuidar; - comentário de limite com prefixo
clean-code-ai:, pra simplificação com teto conhecido.
depois, pedi uma revisão da skill pro ChatGPT e aceitei 3 críticas: abstração com uma implementação só vale quando isola uma fronteira externa real (vendor, I/O), não por "talvez um dia troque"; as ~50 linhas viraram sinal de revisão ("por que ficou grande?"), não limite ("como faço caber?"); e o objetivo é a menor mudança correta, não o menor diff de texto, porque um guard no chamador é um diff menor mas não é a correção certa.
rodei o teste rápido (5 tarefas) de novo com a clean-code-ai, e o juiz reavaliou às cegas as 4 versões juntas. de 200 pontos: clean-code-ai 191, pragmatic-code 190, sem regras 176, ponytail 166. clean-code-ai e pragmatic-code empataram, a diferença de 1 ponto é ruído. o que importa é que a junção não piorou nada. detalhes no RESULTS.md do repo.
como usar#
a skill agora mora no meu repo de skills, com instalação e um teste rápido (5 tarefas pequenas, com e sem regras, avaliadas às cegas por outro modelo): github.com/di0rio/cd-skills.
duas formas, as que eu uso:
-
Claude Code: salva o arquivo como
SKILL.mdnuma pasta em~/.claude/skills/<nome>/(por exemplo~/.claude/skills/clean-code-ai/SKILL.md). o arquivo precisa de frontmatter comnameedescription. odescriptioné o que o agente lê pra decidir quando carregar a skill, então vale ajustar pro seu caso. -
outros agentes: cola o conteúdo no arquivo de regras do projeto, tipo
AGENTS.md,CLAUDE.mdou as regras do Cursor.
o arquivo completo está em ./SKILL.md.
o que ainda falta#
continua sendo uma versão em andamento. já rodei um teste rápido com 5 tarefas (está no repo), mas foi uma rodada só e com tarefas que eu mesmo escrevi. falta usar em projeto real por mais tempo pra saber se o agente segue de verdade, principalmente a parte de escopo. as regras nascem de coisa que me irritou no código gerado, então a lista cresce (e às vezes encolhe). se alguma regra não mudar o comportamento, ela sai: a skill também precisa seguir a própria regra de deletar primeiro.