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

esquema de como versionar skills do Claude Code no Git separando pasta de projeto e pasta pessoal
Resposta rápida

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 .git na 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
Formação Recomendada

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

  1. 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)

  1. Conferir o .gitignore de 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

  1. 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

  1. 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 como anthropic ou claude
  • description: 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

  1. 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

  1. 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-tools no 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:

  1. name dentro do limite de 64 caracteres, só minúsculas, números e hífens, sem palavra reservada
  2. description não vazia, até 1.024 caracteres, escrita com as palavras que o usuário usaria
  3. frontmatter começando na primeira linha do arquivo
  4. nome da pasta inalterado (ou aviso explícito no time, se mudou)
  5. 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

  1. 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

  1. 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

  1. 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

  1. 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 🙂

  1. 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

  1. 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.




Subscribe
Notify of
guest

0 Comentários
Oldest
Newest Most Voted

Formações

Formação SAAS com IA

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