Como versionar suas skills do Claude Code no Git sem bagunçar o repositório

Versionar skills do Claude Code no Git fica simples quando você separa o que é do projeto do que é seu: skill de projeto vive em .claude/skills/<nome>/SKILL.md, pode ser commitada, e quem clona o repositório recebe ela; skill pessoal vive em ~/.claude/skills/<nome>/SKILL.md e é configuração da sua máquina, não do repo. Confira se .claude/ não está no .gitignore, commite o .claude/settings.json e deixe o .claude/settings.local.json de fora. Em pull request, trate description e nome da pasta como interface pública, porque eles mudam quando a skill é acionada e como ela é chamada
Fala aí, beleza? Skill é código, e código que ninguém revisa vira dívida técnica com nome bonito
A fase divertida é a primeira: você cria uma skill, ela funciona, você cria outra, e mais outra
Aí chega o dia em que a skill se comporta diferente do que você lembra, alguém do time diz que ela nem existe na máquina dele, e você não faz ideia de quando o comportamento mudou nem por quê
O problema quase nunca é a skill em si, é a mistura: arquivo pessoal e arquivo de projeto morando no mesmo lugar, sem critério do que viaja no repositório e do que fica só na sua máquina
A lógica aqui é a mesma de versionar o vault no Git antes de deixar a IA mexer nas suas notas: se a IA edita, o Git precisa ver
Neste post eu vou direto ao critério: o que entra no controle de versão, como registrar a mudança de um jeito que dê pra revisar depois, e o que olhar no diff de um SKILL.md quando ele aparece num pull request 🙂
O que você precisa antes de começar
Nada de PC da Nasa aqui, a lista é curta:
- um repositório git já inicializado (o
.gitna raiz do projeto) - o Claude Code instalado e rodando nesse projeto
- pelo menos uma skill funcionando, nem que seja bem simples
E tem um ponto de checagem que vale fazer ANTES de qualquer commit: abra o .gitignore do projeto e confirme que .claude/ não está listado ali
Se .claude/ estiver ignorado, as skills simplesmente não são compartilhadas pelo controle de versão, e você vai passar a tarde tentando entender por que o time não recebe nada
O outro pré requisito é mental: saber diferenciar as duas pastas
| Onde fica | O que é | Vai pro Git? |
|---|---|---|
.claude/skills/<nome>/SKILL.md |
skill do projeto, na raiz do repositório, ao lado do .git |
sim, quem clona o repositório recebe |
~/.claude/skills/<nome>/SKILL.md |
skill pessoal, vale para todos os seus projetos | não, ~/.claude é configuração pessoal |
Guarda essa tabela, porque metade da bagunça que eu vejo por aí é gente commitando o que era pessoal, ou esperando que o que está em ~/.claude chegue no colega por mágica
Formação Vibe Coding
Do Prompt ao Produto: Crie Software Real com IA
- 474 aulas
- 20 projetos
- 39h 27min
Como versionar suas skills do Claude Code no Git, passo a passo
- Decidir o nível: projeto ou pessoal
A pergunta é uma só: essa skill faz sentido pra qualquer pessoa que clonar esse repositório?
Se faz (checklist de deploy do time, padrão de commit do projeto, rotina de migration), ela é do projeto e mora em .claude/skills/<nome>/SKILL.md
Se é o seu jeito de trabalhar, que você quer em qualquer projeto da máquina, ela é pessoal e mora em ~/.claude/skills/<nome>/SKILL.md
meu-projeto/
├── .git/
├── .gitignore
└── .claude/
├── settings.json
└── skills/
└── deploy/
└── SKILL.md
O erro comum deste passo: copiar a skill pessoal pra dentro do projeto "só pra não perder". Arquivo em ~/.claude é configuração pessoal, não do repositório, e quando você duplica o nome nos dois lugares cria uma colisão que te morde depois (falo dela na próxima seção)
- Conferir o
.gitignorede verdade
Abra o arquivo e procure .claude/
git check-ignore -v .claude/skills
Se o comando devolver uma linha apontando a regra, sua skill está sendo ignorada e não viaja com o repo
O erro comum deste passo: assumir que está tudo certo porque o git status não reclamou. Arquivo ignorado não aparece no status, é exatamente esse o silêncio que engana
- Separar configuração do que é pessoal
O .claude/settings.json é o arquivo de configuração de projeto pensado pra ser commitado
O .claude/settings.local.json é pessoal da sua máquina e sobrescreve o settings.json committado, então ele fica de fora
Na primeira vez que o Claude Code escreve o settings.local.json num repositório git que ainda não o ignora, ele adiciona o padrão **/.claude/settings.local.json ao arquivo global de excludes do git
E repara que são dois arquivos diferentes: esse excludes global é configuração do git da sua máquina, mora fora do repositório e nesse caso quem escreve nele é o Claude Code; o .gitignore do projeto é outro arquivo, esse sim versionado junto com o código
O erro comum deste passo: criar o settings.local.json na mão e achar que está protegido. Se foi você que criou o arquivo, o Claude Code não escreveu nada no excludes global por você, então é você que precisa adicionar o arquivo ao .gitignore do projeto
- Deixar a skill em formato revisável
O único arquivo obrigatório de uma skill é o SKILL.md, os demais arquivos de apoio ficam na mesma pasta
E o SKILL.md usa frontmatter YAML entre marcadores ---
---
name: deploy
description: Roda o checklist de deploy em staging, confere build e lista o que mudou desde a última tag
---
Quando esta skill for acionada, siga o checklist abaixo...
Repara numa coisa: o --- de abertura precisa ser a PRIMEIRA linha do arquivo
Se tiver uma linha em branco, um comentário ou um título antes dele, o Claude Code não lê o frontmatter e trata o arquivo inteiro como conteúdo da skill
E aqui vale desfazer uma confusão que aparece direto: quem forma o comando é o nome da PASTA da skill, uma pasta deploy é chamada com /deploy
O campo name do frontmatter é outra coisa, ele tem regras próprias de formato e limite
Como os dois vivem lado a lado, o caminho tranquilo é usar o MESMO valor nos dois (pasta deploy e name: deploy), pra ninguém precisar adivinhar qual é qual na hora de revisar
E os limites dos campos, que valem como regra de revisão:
name: até 64 caracteres, só letras minúsculas, números e hífens, sem tags XML e sem palavras reservadas comoanthropicouclaudedescription: não pode ser vazia e vai até 1.024 caracteres
O erro comum deste passo: deixar um caractere invisível ou uma linha antes do ---. A skill "existe", o arquivo está lá, e nada acontece do jeito que você esperava
- Commitar tratando o nome da pasta como interface pública
O nome da pasta da skill vira o comando: uma pasta deploy é chamada com /deploy
Ou seja, renomear pasta não é refactor cosmético, é quebrar o comando de todo mundo que já usa
git add .claude/skills/deploy
git commit -m "skills: adiciona /deploy (checklist de deploy em staging)"
E no dia em que essa pasta mudar de nome, o commit precisa dizer isso com todas as letras, com o name do frontmatter acompanhando o novo nome:
git commit -m "skills: renomeia a pasta deploy para deploy-staging (/deploy deixa de existir, agora é /deploy-staging)"
O erro comum deste passo: mandar a renomeação junto com dez outras mudanças num commit chamado "ajustes". Seis meses depois ninguém acha onde o comando mudou
- Checar depois do clone ou do merge
Depois que a skill chega na máquina de outra pessoa (ou na sua, depois de um merge), vale confirmar que ela está sendo carregada
A própria documentação sugere o caminho mais simples: perguntar na sessão
What skills are available?
E aproveite pra revisar se a description tem as palavras que o usuário realmente usaria, porque é ela que faz o Claude entender que aquela skill serve pro pedido da vez
O erro comum deste passo: escrever description bonita pra humano e inútil pra busca, tipo "rotina interna do time". Ninguém pede "rotina interna do time", a pessoa pede "faz o deploy em staging"
A skill não é a que você commitou: colisões de nome e precedência
Essa parte aqui resolve os três chamados mais chatos do dia a dia
"Editei a skill do projeto e nada mudou"
Causa: existe uma skill pessoal com o MESMO nome em ~/.claude/skills
A ordem de precedência é: enterprise sobrepõe pessoal, pessoal sobrepõe projeto, e projeto sobrepõe plugin
Traduzindo: sua skill pessoal ganha da skill do projeto, então você pode editar o SKILL.md do repo o dia inteiro que quem roda é a outra
Correção: renomeie uma das duas, ou apague a pessoal se ela já virou versão do projeto
"Tenho .claude/commands/deploy.md e .claude/skills/deploy/SKILL.md"
Causa: nome duplicado entre comando e skill
Nesse caso /deploy roda a skill, porque a skill tem precedência sobre o comando
Correção: escolha um dos dois como fonte da verdade. Manter os dois com o mesmo nome só garante que alguém vai editar o arquivo errado 😀
"A skill sumiu para o time"
Causa: .claude/ no .gitignore
É o clássico: funciona na sua máquina porque o arquivo está lá, e não existe pra mais ninguém porque nunca foi commitado
Correção: tire a regra do .gitignore, commite a pasta de skills e peça pra alguém validar num clone limpo
Como prevenir tudo isso de uma vez
Adote uma convenção de nome por prefixo (algo como proj-deploy pro projeto e meu-deploy pro pessoal) e nunca duplique o mesmo nome entre os dois níveis
E lembra que skill vinda de plugin recebe namespace com o nome do plugin, sendo chamada como /nome-do-plugin:nome-da-skill
Por isso um my-plugin/skills/deploy/SKILL.md vira /my-plugin:deploy e convive numa boa com o /deploy do seu projeto, sem colidir
Como revisar mudança de skill em um pull request
Aqui vai o pulo do gato: um diff de SKILL.md parece "só texto", mas ele muda comportamento igual código muda
O que olhar, na ordem:
- mudou a
description? então mudou QUANDO o Claude aciona a skill. É o campo que decide se ela entra em cena no pedido do usuário, tratar como mudança de comportamento - mudou o nome da pasta? então mudou o comando. A pasta vira
/nome-da-skill, e renomear quebra o atalho de todo mundo - entrou
allowed-toolsno frontmatter? vale saber que esse campo só é suportado no Claude Code via CLI e não se aplica a skills usadas pelo SDK. Se o time também consome essa skill pelo SDK, o campo não vai fazer o que a pessoa acha que faz - entrou
disable-model-invocation: true? isso impede que o Claude acione a skill sozinho, deixando ela só pra invocação manual. É uma decisão legítima, mas silenciosa: de fora parece que a skill "parou de funcionar" - o
---continua na primeira linha? parece bobo, mas é o tipo de coisa que passa batido em PR grande e derruba o frontmatter inteiro
Checklist curto de revisor, pra colar no template de PR:
namedentro do limite de 64 caracteres, só minúsculas, números e hífens, sem palavra reservadadescriptionnão vazia, até 1.024 caracteres, escrita com as palavras que o usuário usaria- frontmatter começando na primeira linha do arquivo
- nome da pasta inalterado (ou aviso explícito no time, se mudou)
- arquivos de apoio na mesma pasta da skill
O critério do que exige aviso pro time é simples: mudou nome de pasta, description ou acionamento automático, avisa. Mudou só o corpo das instruções, segue o fluxo normal de review
Na prática: o que aprendi versionando skills em projeto real
Receber um conjunto de skills pronto vindo de um repositório não é novidade, eu já falei aqui do repositório de skills do Superpowers
Mas foi instalando skills prontas que eu entendi por que organização de pasta importa tanto
No vídeo eu instalo uma skill de design via script, e a primeira pergunta do instalador foi em quais editores de IA a skill ficaria disponível
Deixei marcadas só as duas que uso no dia a dia
Depois veio a pergunta que interessa pra este post: instalar só naquele projeto ou de forma global?
O efeito prático é direto: instalada no projeto, a skill não fica acessível fora dali; instalada global, ela aparece em qualquer outro projeto da máquina
Meu critério foi o tipo de skill. Se ela só vai ser usada num projeto específico, não compensa deixar global
Escolhi também instalar por link simbólico em vez de baixar o arquivo da skill pra dentro da máquina, e dá pra ver na demonstração que a pasta ficou com o link apontando pra skill, não com o arquivo em si
Aí veio o preço de ter marcado mais de um editor: o instalador criou pastas de outros editores dentro do projeto
Apaguei as pastas extras e deixei só a do Claude Code, e é aqui que mora a lição chata: dava pra evitar essa limpeza selecionando apenas o Claude Code lá no começo, o resultado final seria o mesmo
Depois de instalada, abri o Claude Code no mesmo projeto e a skill já estava disponível pra uso
Outra coisa que notei: dizer explicitamente no prompt qual skill deve ser usada ajuda o editor a encontrar e ativar ela
E o resultado ficou visível na comparação, a página gerada sem a skill veio com ícone genérico e emoji com cor mal escolhida, enquanto a versão com a skill de design ficou bem mais alinhada a padrões de design
O veredito honesto, pensando em versionamento: conjunto de skills pronto é ótimo pra começar, mas o que resolve a bagunça é você decidir o escopo ANTES de instalar
E se a intenção é que o time inteiro receba a skill no clone, o que precisa viajar no Git é arquivo de verdade dentro de .claude/skills do projeto, não um link que só existe na sua máquina
No vídeo você vê a instalação passo a passo, a escolha entre projeto e global, a pasta ficando com link simbólico e a comparação lado a lado da página gerada com e sem a skill de design
Quando a skill vira plugin: versão de verdade e validação em CI
Enquanto a skill vive num repositório só, commitar o SKILL.md resolve
Quando ela precisa circular entre vários repositórios, dá pra subir de nível e empacotar como plugin, que aí você ganha identidade, versão e validação automatizada
- Criar o manifesto
O manifesto de plugin fica em .claude-plugin/plugin.json e define a identidade: name (obrigatório), description e version
{
"name": "skills-do-time",
"description": "Skills de deploy e revisão usadas pelos projetos do time",
"version": "3.1.0"
}
O erro comum deste passo: esperar esse mesmo campo de versão no SKILL.md avulso. O versionamento por campo é do manifesto do plugin, não da skill solta
- Validar antes de distribuir
claude plugin validate ./meu-plugin
A saída é ✔ Validation passed (ou passou com avisos), e existe a flag --strict pra tratar aviso como erro
claude plugin validate ./meu-plugin --strict
Esse comando pode rodar em CI, que é exatamente o que você quer: PR que mexe em skill empacotada não passa sem validação
O erro comum deste passo: deixar rodar sem --strict e ignorar aviso por meses, até o aviso virar problema de verdade
- Publicar num catálogo
Um catálogo (marketplace) de plugins fica em .claude-plugin/marketplace.json e pode ser distribuído por repositório git, com fontes que incluem github, url e git-subdir
É ele que dá descoberta centralizada, rastreio de versão e atualização automática
Um repositório GitHub com esse arquivo é registrado no formato owner/repo
- Registrar e instalar
/plugin marketplace add owner/repo
/plugin install nome@marketplace
E pra manter atualizado:
/plugin update
/plugin marketplace update
Se o resumo da instalação pedir, roda /reload-plugins pra ativar
O erro comum deste passo: achar que o plugin não funciona quando na verdade faltou o /reload-plugins que o próprio resumo pediu 🙂
- Resolver o clone em máquina que não tem SSH configurado
Fontes no atalho owner/repo do GitHub são clonadas por SSH por padrão
Se isso te trava, a variável CLAUDE_CODE_PLUGIN_PREFER_HTTPS=1 faz clonar por HTTPS, e os comandos de plugin reutilizam os credential helpers do git que você já tem configurados
O erro comum deste passo: sair configurando credencial nova sem lembrar que o git da máquina já tem helper configurado
- Travar a versão que você testou
Por padrão uma dependência de plugin acompanha a última versão disponível
Se você quer previsibilidade, use restrição de versão em faixa semver pra segurar a dependência numa versão testada, seguindo a convenção de tag git {plugin-name}--v{version}
Tome cuidado com um detalhe: a resolução por tag só vale pra fontes git
Pra dependências vindas de npm, archive ou command a restrição não controla o que é baixado, mas ainda é checada no carregamento, e o plugin dependente é desabilitado com dependency-version-unsatisfied se a versão instalada não satisfizer a faixa
O erro comum deste passo: ver dependency-version-unsatisfied e sair caçando bug no seu código, quando é só a faixa semver brigando com o que está instalado
Próximo passo
A regra que resolve quase toda a bagunça cabe em duas linhas
Primeira: separa o que é do projeto (.claude/skills, commitado) do que é seu (~/.claude/skills, fora do repo)
Segunda: trata description e nome da pasta como interface pública, porque um decide quando a skill é acionada e o outro decide como ela é chamada
O próximo passo é concreto e leva cinco minutos: abre o .gitignore hoje, confirma que .claude/ não está lá, commita as skills do projeto e, na próxima sessão, pergunta What skills are available? pra validar que chegou tudo certinho
Depois disso, revisar mudança de skill em PR vira rotina, e não arqueologia
Tem mais conteúdo sobre Claude Code aqui no blog, então cola por aqui que vem coisa boa por aí…
até o próximo post! 😀
Perguntas frequentes
Posso commitar uma skill pessoal junto com as skills do projeto?
Dá pra copiar o arquivo pra dentro de .claude/skills, mas não é o ideal: arquivo em ~/.claude é configuração pessoal, não do repositório. Se ela faz sentido pra qualquer pessoa que clonar o projeto, recrie como skill de projeto; se é só o seu jeito de trabalhar, deixa ela em ~/.claude/skills mesmo.
Por que a skill não aparece para quem clona o repositório?
Na maioria das vezes é o .claude/ listado no .gitignore, e um arquivo ignorado não aparece nem no git status pra te alertar. Rode git check-ignore -v .claude/skills pra confirmar: se devolver uma linha com a regra, a pasta está sendo ignorada e não viaja com o repositório.
O que colocar no controle de versão: settings.json ou settings.local.json?
Só o .claude/settings.json deve ir pro Git, porque é a configuração pensada pra ser commitada. O .claude/settings.local.json é pessoal da máquina, sobrescreve o settings.json committado e fica de fora do repositório.
O que acontece se eu tiver uma skill com o mesmo nome no projeto e na pasta pessoal?
A ordem de precedência é enterprise sobrepõe pessoal, pessoal sobrepõe projeto, e projeto sobrepõe plugin. Então uma skill em ~/.claude/skills com o mesmo nome de uma skill do projeto é a que roda, e isso costuma confundir quem está revisando o comportamento no PR.
Como confirmar que a skill foi carregada depois de um merge ou clone?
O caminho mais simples é perguntar na própria sessão: "What skills are available?". Vale conferir se a description da skill tem as palavras que você usaria pra chamar ela, porque é isso que o Claude usa pra decidir quando acionar.
Preciso versionar mais arquivos além do SKILL.md?
O único arquivo obrigatório de uma skill é o SKILL.md; os demais arquivos de apoio na mesma pasta são opcionais. Se a skill usa algum desses arquivos extras, eles entram no mesmo commit, senão o SKILL.md sozinho já é suficiente.
Formações
Formação SAAS com IA
Tire usas ideias do papel criando softwares com IA, integre pagamentos e lance seu projeto!
- 291 aulas
- 18 projetos
- 24h 17min
Blog | Mais populares
As diferenças de var, let e const
Checklist de segurança n8n VPS pública: guia essencial para proteger sua instalação
Checklist de segurança n8n VPS pública: guia essencial para proteger sua instalação A popularidade da automação de processos com o n8n está em alta, principalmente […]
Como fazer redirecionamento com PHP
Neste artigo você vai aprender a como fazer redirecionamento com PHP, utilizaremos abordagens fáceis de entender e de aplicar Fala programador(a), beleza? Bora aprender mais […]
