rust-qc

Use esta habilidade sempre que sua resposta contiver código Rust ou configurações Cargo/clippy/rustfmt, ou um veredito sobre código Rust existente. Tarefas Rust aparentemente simples ainda precisam dela — ela contém as convenções necessárias e uma verificação fmt/clippy/doc/test que toda alteração Rust deve passar.

O que é rust-qc?

O skill `rust-qc` para agentes de IA (como Claude Code, Cursor, Codex) estabelece um padrão unificado para escrever, modificar e auditar código Rust. Ele combina regras do Rust Style Guide, Rust API Guidelines, Microsoft Pragmatic Rust Guidelines (2026.6), Google Rust Style Guide e práticas de projetos como memchr e ripgrep. O skill opera em três modos: Criar (novos módulos, tipos, funções), Modificar (alterações em código existente) e Auditar (revisão detalhada). Para cada modo, ele executa um fluxo rigoroso: estabelece contexto (lendo Cargo.toml, rustfmt.toml, clippy.toml e outras configurações do projeto), depois aplica regras não negociáveis como formatação via rustfmt, documentação SAFETY para código unsafe, tratamento correto de erros (Result vs panic), e proibição de unwrap() em produção. O skill também executa scripts de verificação (scripts/check.sh e audit_scan.py), compara com uma linha de base para detectar regressões, e realiza testes de fuzzing com entradas maliciosas. O resultado é um relatório estruturado com achados categorizados como Crítico, Principal, ou Menor, incluindo correções propostas.

Funciona com✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/coryj627/rust-qc/tree/main/.agents/skills/rust-qc

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

Rust QC

Este skill estabelece um padrão para código Rust e o aplica em três modos. As regras vêm do Rust Style Guide, do Rust API Guidelines, do Microsoft Pragmatic Rust Guidelines (2026.6), do Google Rust Style Guide e das práticas visíveis em memchr, jiff, ripgrep, fd e dua-cli. Onde essas fontes discordam, references/precedence.md registra a decisão para que você nunca precise reabrir a discussão.

Passo 1: Estabelecer contexto (todos os modos)

Faça isso antes de escrever ou julgar qualquer código. Pare e relate se uma pré-condição falhar; não adivinhe sobre um toolchain ou manifest ausente.

  1. Encontre a raiz do crate (o Cargo.toml mais próximo). Observe se é um workspace, uma biblioteca, um binário, ou ambos, e se é publicado (publish = false ou consumido apenas dentro do workspace ou através de FFI significa interno).
  2. Leia as regras próprias do projeto primeiro, porque elas substituem os padrões deste skill: rustfmt.toml ou .rustfmt.toml, clippy.toml, [lints] e [workspace.lints] em Cargo.toml, edition, rust-version (MSRV), rust-toolchain.toml, CONTRIBUTING.md, AGENTS.md ou CLAUDE.md, e qualquer AI_POLICY.md. Se AI_POLICY.md ou CONTRIBUTING.md restringir contribuições de IA ou agentes, avise o usuário antes de produzir alterações destinadas a esse repositório.
  3. Classifique o código como biblioteca ou aplicação. As regras de design de API são obrigatórias para bibliotecas e recomendações fortes para aplicações, que devem favorecer a simplicidade em vez da generalidade.
  4. Observe as plataformas. Se rust-toolchain.toml listar alvos ou o código for pesado com portões no estilo #[cfg(windows)] para uma plataforma diferente deste host, execute a verificação com --target <triple> também (lint e documenta para esse alvo; testes são ignorados). Avisos como código morto que aparecem apenas no host por causa de portões de plataforma são artefatos do host, não achados.
  5. Execute scripts/check.sh <crate-root> uma vez para registrar a linha de base. Você precisa dela para distinguir suas próprias regressões de dívidas pré-existentes. Use --features "<list>" em vez do padrão --all-features quando o crate tiver features mutuamente exclusivas.

Não instale toolchains, componentes ou ferramentas (nightly, Miri, cargo-hack) e não use a rede além de buscar crates a menos que o usuário peça. Quando uma verificação precisar de algo ausente, diga e recomende.

Passo 2: Escolher o modo

Criar quando o usuário quiser novas funções, métodos, tipos, módulos ou crates. Siga "Criando código" abaixo.

Modificar quando o usuário quiser alterar código existente: uma funcionalidade, refinamento, correção de bug, refatoração ou remediação de achados de auditoria. Siga "Modificando código" abaixo.

Auditar quando o usuário quiser código existente revisado, avaliado ou verificado, com problemas identificados e correções propostas. Siga "Auditando código" abaixo. Auditoria não altera código a menos que o usuário peça; ela produz achados.

Uma solicitação pode abranger modos ("audite este módulo e corrija o que encontrar"). Execute a auditoria primeiro, relate, depois mude para modificar para as correções.

Regras inegociáveis

Estas se aplicam em todos os modos. O conjunto completo de regras, com IDs, vive nos arquivos de referência listados no final.

  • Formatação é trabalho do rustfmt. Nunca formate manualmente contra o rustfmt. Nunca adicione #[rustfmt::skip] exceto para alinhamento deliberado (tabelas, matrizes) ou código gerado.
  • Código é seguro. Código seguro não deve ser capaz de causar comportamento indefinido. Cada bloco unsafe tem um comentário // SAFETY: diretamente acima dele explicando por que cada pré-condição é válida. Cada unsafe fn e unsafe trait tem uma seção de documentação # Safety. Use unsafe apenas para FFI, uma necessidade de desempenho medida por benchmark, ou uma abstração nova, e nunca para contornar Send, Sync ou lifetimes. Veja references/unsafe.md.
  • Erros versus pânicos. Falhas recuperáveis causadas por entrada ou ambiente retornam Result (ou Option quando a causa é óbvia). Bugs de programação detectados causam pânico. Código de biblioteca nunca entra em pânico com entrada do chamador que poderia razoavelmente ser inválida. Veja references/errors.md.
  • Erros de biblioteca permitem que os chamadores façam ramificações sem analisar texto. Um tipo de erro concreto com um método kind() retornando um enum #[non_exhaustive] público, ou predicados is_*(). Campos privados são corretos; um kind privado sem accessor é um defeito. Mensagens apontam para o token e posição ofensivos, e nunca copiam toda a entrada.
  • Nenhum unwrap() puro em código de produção. Use ?, correspondência de padrões, ou expect("...") cuja mensagem afirma por que o invariante é válido. unwrap() é aceitável em testes. Exemplos de documentação usam ? com a linha oculta # Ok::<(), Box<dyn std::error::Error>>(()).
  • Cada nova dependência é um custo, dev-dependencies incluídas. Adicione uma apenas quando ela remove complexidade real ou fornece correção que você não pode escrever razoavelmente (Unicode case folding é uma boa razão; um framework de teste de propriedades para um parser de 100 linhas não é). Diga por que em seu relatório.
  • Estrutura corresponde ao tamanho. Não crie um módulo para uma função pequena e seu tipo de erro; um módulo merece seu arquivo com um conceito distinto e vários itens ou algumas centenas de linhas.
  • Sobrescritas de lint usam #[expect(lint, reason = "...")], não #[allow], para que sobrescritas obsoletas apareçam.
  • Itens públicos são documentados, a primeira frase é uma linha de cerca de 15 palavras, e funções incluem seções # Errors, # Panics e # Safety sempre que aplicável. Veja references/documentation.md.
  • Tipos públicos implementam Debug. Tipos destinados a serem lidos por pessoas também implementam Display.
  • Comentários explicam o porquê, não o quê. Se um comentário reafirma o código, exclua-o. O comentário do alocador do ripgrep em crates/core/main.rs é o modelo: decisão, motivo e as condições sob as quais ele se aplica.
  • Nenhum diagrama ASCII-art ou caracteres de desenho de caixa em comentários ou documentação. Descreva a estrutura em frases; desenhos são ilegíveis com um leitor de tela e apodrecem quando o código muda. (Convenção da equipe, não upstream.)
  • Nenhum conteúdo de diário de design na documentação. A documentação descreve o comportamento atual, não como o código veio a ser ou quais diretrizes foram seguidas.
  • Testes verificam comportamento. Nenhum teste que reafirme uma constante ou espelhe os ramos da implementação.

Criando código

Trabalhe de fora para dentro: tipos e assinaturas primeiro, depois documentação, depois implementação, depois testes. Escrever o comentário de documentação antes do corpo é a maneira mais rápida de descobrir uma API confusa.

  1. Posicione-o. Coloque o item no módulo que possui seu conceito; em um crate pequeno isso é frequentemente lib.rs. Novos módulos são nomeados após seu tipo principal e só criados quando o código justifica um (ORG-19). Veja references/organization.md.
  2. Modele com tipos. Newtypes para valores que são fáceis de misturar ou carregam invariantes, com construtores que impõem o invariante. Um enum em vez de um parâmetro bool cujo significado não é óbvio no local da chamada. Campos nomeados sobre tuplas. Torne estados inválidos irrepresentáveis.
  3. Modele a assinatura. Pegue emprestado o que você só lê (&str, &[T], &Path, Option<&T>), tome posse apenas quando você armazena ou consome. Em bibliotecas, aceite impl AsRef<Path> ou impl IntoIterator onde remove atrito; em aplicações, mantenha tipos concretos. Builders para tipos com várias configurações opcionais, validando em build(). Veja references/api-design.md.
  4. Nomeie-o. Maiúsculas/minúsculas RFC 430; conversões as_ / to_ / into_; construtores new, with_*, try_new; getters foo(). Nenhuma palavra vaga (Manager, Service, Factory, Helper, Util), e nenhum nome que colida com um significado existente na mesma interface (NAME-9).
  5. Documente-o de acordo com references/documentation.md, incluindo um exemplo executável para itens públicos, e a unidade de qualquer posição ou comprimento que você retorna.
  6. Implemente-o. Funções de propósito único. Um loop for simples sobre uma cadeia de combinadores quando a cadeia precisa de condicionais ou estado externo; combinadores quando eles substituem lógica escrita à mão (any, position, sum). Anotações de tipo onde a inferência deixaria um leitor adivinhando. Texto humano recebe tratamento ciente de Unicode: correspondência sem distinção entre maiúsculas e minúsculas usa Unicode case folding, ou documenta suas lacunas (API-27).
  7. Lide com erros de acordo com references/errors.md: em bibliotecas um tipo de erro concreto com um kind ou predicados públicos; em aplicações anyhow com .context().
  8. Teste-o de acordo com references/testing.md: testes unitários inline, testes de integração sob tests/, e verificações de invariantes amplas que não precisam de novas dependências (enumere entradas curtas, ou um loop com semente contra uma referência ingênua).
  9. Verifique com a verificação abaixo.

Modificando código

O objetivo é a menor alteração correta que deixe o código tocado pelo menos tão claro quanto você o encontrou.

  1. Leia antes de editar. Leia a função inteira, seus chamadores, seus testes e a API vizinha. Identifique convenções locais (estilo de importação, tipo de erro, estilo de cabeçalho de documentação como # Example versus # Examples, largura de linha, densidade, nomes de parâmetros e chaves) e corresponda a elas, mesmo onde os padrões deste skill diferem.
  2. Correções de bug começam com um teste com falha que cobre a classe do bug. Reproduza a entrada relatada, depois adicione os casos vizinhos que a mesma causa raiz quebra (mais elementos, outras ordenações, combinações). Veja-os falhar, corrija a causa raiz, veja-os passar. Se o projeto mantiver testes de regressão em um lugar (ripgrep's tests/regression.rs), adicione o seu lá.
  3. Corrija a causa, não o sintoma. Um novo unwrap_or_default(), clone() ou retorno antecipado que silencia uma falha não é uma correção a menos que você possa explicar por que o caminho original estava errado. Coloque um comentário de uma linha na correção se o motivo não for óbvio a partir do código.
  4. Fique cirúrgico. Não renomeie, reordene ou reformate código que você não foi solicitado a tocar. Liste problemas não relacionados para o usuário em vez de corrigi-los silenciosamente.
  5. Mantenha APIs e ABIs públicas estáveis a menos que o usuário aprove uma alteração disruptiva. Adicionar um campo a uma estrutura pública com campos públicos, uma variante a um enum público exaustivo, um método de trait obrigatório ou alterar um contrato FFI é disruptivo.
  6. Atualize a documentação e os testes com o código. Uma assinatura ou comportamento alterado significa # Errors, # Panics, exemplos e testes alterados na mesma alteração.
  7. Formatação: se a linha de base estava limpa com rustfmt, execute cargo fmt. Se não estava, formate apenas o que você alterou e avise o usuário. Se rustfmt.toml usar opções exclusivas do nightly (rustfmt estável avisa que são "only available in nightly channel"), o padrão do projeto é cargo +nightly fmt; use-o se estiver instalado, e caso contrário não formate nada automaticamente e diga isso, porque o rustfmt estável reescreveria o código contra as configurações do projeto.
  8. Remediação de uma auditoria: corrija achados em ordem de gravidade, um achado por alteração lógica, e nomeie o achado em seu resumo.
  9. Verifique com a verificação abaixo e confirme que você não introduziu novos avisos em relação à linha de base, em cada alvo que você verificou no passo 1.

Auditando código

  1. Execute scripts/check.sh --audit <crate-root> (mais --target conforme passo 1). A passagem --audit relata, com acessibilidade da API pública, unsafe não documentado, documentação ausente e seções # Errors/# Panics, unwrap fora de testes, #[allow] sem motivo, dbg!/todo!, importações glob, e asserções sem mensagens. Relate esses resultados de higiene de forma compacta: um achado Menor por categoria (documentação, Debug, comentários SAFETY, configuração de lint), cada um com uma contagem e as poucas instâncias que mais importam. Uma etapa de verificação que falha apenas porque o toolchain aqui é mais novo do que aquele que o CI do projeto ou rust-toolchain.toml usa é desvio de toolchain: um achado Menor, não um Principal.

  2. Execute python3 -I scripts/audit_scan.py <crate-root> para o que o clippy não pode ver: reexportações glob, nomes de tipo com palavras vagas, comentários ASCII-art, documentação de histórico de design, tabelas de parâmetros, TODOs puros, mensagens expect vazias e macros de impressão em código de biblioteca. Confirme cada acerto lendo o código; descarte falsos positivos.

  3. Teste o comportamento como os usuários o encontram. É aqui que a maioria dos bugs voltados para o usuário em crates reais é encontrada, então gaste a maior parte da auditoria aqui e no passo 5. Leia a documentação, especificação e testes do crate para listar as funcionalidades de entrada que ele afirma lidar. Para cada uma, construa uma pequena entrada realista que os testes existentes não cobrem, execute-a através da API pública de um crate descartável fora do workspace e compare a saída com o que um usuário deveria obter. Cubra as funcionalidades que o formato permite, mas que as fixtures ignoram:

    • valores herdados, indiretos ou padrão
    • duplicatas
    • partes opcionais ou ocultas
    • danos leves que outras ferramentas toleram
    • texto não ASCII e codificações legadas
    • tamanhos grandes mas legítimos

    Relate cada problema confirmado com a entrada que o mostra.

  4. Teste contra entradas não confiáveis. Para cada função pública que analisa bytes ou texto não confiáveis, alimente-a com toda entrada curta sobre um alfabeto relevante ou alguns milhões de mutações aleatórias com semente, e capture pânicos. Também tente estruturas artificiosas que fazem o trabalho crescer mais rápido que o tamanho da entrada (referências compartilhadas ou recursivas, aninhamento profundo) sob um tempo limite.

  5. Leia o código para o que ferramentas não podem julgar: solidez de cada bloco unsafe, design de erro, formato da API, limites de módulo, nomenclatura, qualidade do teste e se comentários explicam o porquê. Em código que fala com o sistema operacional, também verifique:

    • pânicos em uma chamada de sistema, I/O ou falha de ambiente (assert! ou unwrap em um valor de retorno, uma variável de ambiente ou campo passwd não UTF-8)
    • código entre fork e exec (closures pre_exec) ou em um manipulador de sinal que aloca, trava, formata, registra ou sai, nenhum dos quais é seguro para sinal assíncrono
    • descritores de arquivo ou handles vazados, e sinais enviados a um ID de processo que pode ter sido coletado e reutilizado
    • conversões de estreitamento e aritmética não verificada em tamanhos, contagens e coordenadas

    Use references/audit-checklist.md.

  6. Relate usando o formato abaixo. Proponha uma correção concreta para cada achado.

Os passos 1 e 2 são um piso rápido, não a auditoria: gaste não mais do que cerca de um quinto do tempo neles. Uma auditoria que lista principalmente melhorias de lint, documentação e s...

[truncado para tradução]

Habilidades Relacionadas