Uma skill no Claude Code é uma pasta com um arquivo SKILL.md: um frontmatter YAML que diz quando usar e um corpo em Markdown com as instruções. O Claude Code carrega no início só o nome e a descrição de cada skill; o corpo entra no contexto quando a skill é invocada, por você com /nome ou pelo próprio Claude quando o pedido casa com a descrição. Skills seguem o padrão aberto Agent Skills, e os antigos comandos em .claude/commands/ viraram skills: os dois formatos criam o mesmo /nome.
Este post é um dos guias práticos do guia de Claude Code. Vamos construir uma skill real, /nova-adr, que registra uma decisão de arquitetura no formato do projeto, com um script que descobre o próximo número livre.
Decida se é skill, CLAUDE.md ou hook
A documentação de skills dá o critério: crie uma skill quando você vive colando as mesmas instruções, checklist ou procedimento no chat, ou quando um trecho do CLAUDE.md virou procedimento em vez de fato.
| Tipo de conteúdo | Onde vai |
|---|---|
| Fato que vale em toda sessão ("porta 5433, não 5432") | CLAUDE.md |
| Procedimento usado às vezes ("como registrar uma ADR") | Skill |
| Regra que precisa valer sempre ("nunca edite migração versionada") | Hook |
| Conexão com sistema externo (banco, API, ADRs via busca) | Servidor MCP |
Skill e MCP se complementam: a visão geral de recursos resume que o MCP conecta o Claude a serviços externos e a skill ensina como usar esses serviços. A skill deste post usa o servidor MCP de ADRs quando ele está conectado.
Crie a pasta da skill
mkdir -p .claude/skills/nova-adr/scriptsOnde a pasta fica decide quem vê a skill:
| Local | Caminho | Vale para |
|---|---|---|
| Pessoal | ~/.claude/skills/<nome>/SKILL.md | Você, em todos os projetos |
| Projeto | .claude/skills/<nome>/SKILL.md | Todo mundo no repositório (vai pro git) |
| Plugin | <plugin>/skills/<nome>/SKILL.md | Quem instala o plugin, como /plugin:nome |
O nome da pasta vira o comando. O campo name do frontmatter, se existir, também.
Escreva o SKILL.md
---
name: nova-adr
description: Registra uma decisão de arquitetura como um novo ADR em docs/adr, no modelo do projeto. Use quando pedirem para registrar, documentar ou formalizar uma decisão técnica.
argument-hint: "[título da decisão]"
allowed-tools: Read Write Bash(python3 ${CLAUDE_SKILL_DIR}/scripts/proximo_adr.py *)
---
## ADRs existentes e próximo número
!`python3 ${CLAUDE_SKILL_DIR}/scripts/proximo_adr.py ${CLAUDE_PROJECT_DIR}/docs/adr`
## Como registrar
Título pedido: $ARGUMENTS (se estiver vazio, pergunte o título antes de seguir).
1. Procure ADRs relacionados antes de escrever. Se o servidor MCP `adrs` estiver conectado, use a ferramenta `buscar_adrs`; se não, use Grep em `docs/adr/`. Cite os relacionados na seção Contexto.
2. Crie o arquivo com o próximo número indicado acima, no formato `NNNN-titulo-em-kebab-case.md`, seguindo o modelo em `${CLAUDE_SKILL_DIR}/modelo.md`.
3. Preencha só com o que foi discutido nesta conversa. O que não foi discutido fica como "a preencher". Não invente alternativas.
4. Status sempre `Proposed`. Quem aceita é uma pessoa.
5. Termine mostrando o caminho do arquivo criado.Linha por linha:
descriptioné o gatilho. É o que o Claude lê pra decidir se carrega a skill sozinho. Ponha o caso de uso principal primeiro e as palavras que alguém usaria pedindo isso ("registrar", "documentar", "decisão técnica"). Descrição ewhen_to_usejuntas são cortadas em 1.536 caracteres na listagem.argument-hintaparece no autocomplete. O que vier depois de/nova-adrsubstitui$ARGUMENTSno corpo.!seguido de comando entre crases é injeção de contexto. O Claude Code roda o comando antes de mandar a skill pro modelo e troca a linha pela saída. O Claude recebe a lista de ADRs pronta, não a instrução de ir buscar.${CLAUDE_SKILL_DIR}é a pasta da skill, e${CLAUDE_PROJECT_DIR}é a raiz do projeto. Os dois são substituídos no corpo e nas regras de Bash doallowed-tools.allowed-toolslibera ferramentas sem pedir permissão, só no turno em que a skill é invocada. A regra de Bash repete exatamente o comando do corpo, com a mesma variável: é o padrão que a documentação mostra pra rodar um script embutido sem prompt.
Esse último ponto não é opcional. Comandos injetados nunca pedem permissão enquanto a skill é montada: fora do modo auto, se a checagem de permissão do comando não der "allow", a invocação é abortada com Shell command permission check failed. Sem a regra em allowed-tools, a skill quebra na primeira linha.
O corpo segue o conselho da documentação: curto e em forma de instrução permanente. Depois que a skill carrega, o conteúdo fica na conversa nos turnos seguintes, e o Claude Code não relê o arquivo. Cada linha é custo recorrente de contexto.
Adicione o script e o modelo
#!/usr/bin/env python3
"""Lista os ADRs existentes e diz qual é o próximo número livre."""
import re
import sys
from pathlib import Path
pasta = Path(sys.argv[1] if len(sys.argv) > 1 else "docs/adr")
if not pasta.is_dir():
print(
f"Pasta {pasta} não existe. Crie-a antes, ou confirme o caminho com o usuário."
)
sys.exit(0) # sair com erro abortaria a skill; a mensagem orienta o Claude
adrs = sorted(p for p in pasta.glob("*.md") if re.match(r"\d{4}-", p.name))
for p in adrs:
titulo = p.read_text(encoding="utf-8").splitlines()[0].lstrip("# ").strip()
print(f"- {p.name}: {titulo}")
proximo = int(adrs[-1].name[:4]) + 1 if adrs else 1
print(f"\nPróximo número: {proximo:04d}")Repare no sys.exit(0) quando a pasta não existe: em vez de quebrar, o script imprime uma frase que vira instrução pro Claude. Arquivos de apoio como este não entram no contexto; o script é executado e só a saída aparece.
O modelo fica ao lado, em .claude/skills/nova-adr/modelo.md, e só é lido quando a skill manda:
# ADR-NNNN: Título
## Status
Proposed
## Context
Qual problema força a decisão. ADRs relacionados.
### Options Considered
- Opção A: prós e contras
- Opção B: prós e contras
## Decision
O que foi decidido, em uma frase, e por quê.
## Consequences
O que fica mais fácil, o que fica mais difícil, o que precisa ser revisto e quando.Rodando o script na pasta de exemplo, com quatro ADRs reais do capivaOS, é isto que o Claude recebe no lugar da linha !:
- 0008-phase-guard-hook-enforcement.md: ADR-0008: Hook-Enforced Phase Guards Parsing sprint-state.md Directly
- 0010-fast-lane-pipeline.md: ADR-0010: Fast-Lane Pipeline for Small, Low-Risk Tasks
- 0011-slim-always-loaded-layer.md: ADR-0011: Slim the Always-Loaded Instruction Layer
- 0014-autonomy-contract.md: ADR-0014: The Autonomy Contract — Delegated Gates, Isolation-First Context
Próximo número: 0015Valide o frontmatter
Um YAML quebrado não impede a skill de carregar: ela carrega com os metadados vazios. O /nova-adr continua funcionando, mas o Claude nunca vai acioná-la sozinho, porque não há description pra comparar. Pra pegar isso antes, a partir da v2.1.233:
$ claude plugin validate .claude/skills
Validating components in: .../.claude/skills
✔ Validation passedCom um frontmatter quebrado de propósito, o mesmo comando falha e explica a consequência:
✘ Found 1 error:
❯ frontmatter: YAML frontmatter failed to parse: YAML Parse error: Unexpected token. At runtime this skill loads with empty metadata (all frontmatter fields silently dropped).
✘ Validation failedVale pôr no CI junto com o lint de CLAUDE.md. Outra armadilha silenciosa: nome de campo errado (allowed_tools com underscore, por exemplo) é ignorado sem erro.
Teste nos dois modos
Dentro do Claude Code, invoque direto:
/nova-adr Usar Postgres como fila em vez de RedisAntes de abrir uma sessão, dá pra confirmar que o Claude Code achou a skill. Sem login, claude -p "/nova-adr Usar Postgres" --debug-file debug.log termina em Not logged in · Please run /login, mas o log já registra a descoberta (Claude Code 2.1.296):
[DEBUG] Loading skills from: managed=/etc/claude-code/.claude/skills, user=.../.claude/skills, project=[.../.claude/skills]
[DEBUG] Loaded 1 unique skills (1 unconditional, 0 conditional, managed: 0, user: 0, project: 1, additional: 0, legacy commands: 0)project: 1 é a sua skill. Com project: 0, o caminho ou o nome do arquivo está errado. A linha ! não roda nesse teste; ela só é executada quando a skill é de fato invocada numa sessão logada.
E teste o disparo automático com um pedido que casa com a descrição, sem citar a skill: "registra essa decisão de usar Postgres como fila". Se o Claude não acionar, a documentação sugere três coisas: conferir se a descrição tem as palavras que as pessoas usam, perguntar "What skills are available?" pra ver se ela aparece, e reformular o pedido.
Se a skill é do tipo que só deve rodar quando você pede (deploy, commit), adicione disable-model-invocation: true. Se é conhecimento de fundo que só o Claude deve usar, user-invocable: false tira ela do menu /.
Como usamos na Capiva
O capivaOS é, em boa parte, um conjunto de skills: as fases do fluxo (grill-spec, plan, implement, test-verify, entre outras) estão na pasta skills do repositório. O ADR-0011 registra por que isso importa: os exemplos completos de cada fase moraram por um tempo em arquivos sempre carregados, e foram movidos pra carregar só na fase que precisa deles. A camada sempre carregada caiu de ~26,4 mil pra ~16,9 mil tokens (estimativa por caracteres/4), sem cortar uma linha dos exemplos.
Checklist de troubleshooting
- [ ] A skill não aparece no
/. Confira o caminho:.claude/skills/<nome>/SKILL.md, com o nome do arquivo em maiúsculas. O---de abertura precisa ser a primeira linha do arquivo. - [ ] O Claude nunca aciona sozinho. YAML quebrado (rode
claude plugin validate),descriptionvaga, oudisable-model-invocation: true. - [ ] Aciona demais. Deixe a descrição mais específica ou passe pra invocação manual.
- [ ]
Shell command permission check failed. O comando injetado com!não está liberado. Adicione a regra exata emallowed-tools, ou confira se uma regra de deny não está pegando. - [ ] O Claude para de seguir a skill no meio da sessão. Se é regra que precisa valer sempre, transforme em hook (dá pra declarar no próprio frontmatter, campo
hooks). Depois de uma compactação, só o começo de cada skill é mantido: invoque de novo e ponha o essencial no topo. - [ ] Descrições cortadas com muitas skills instaladas. A listagem tem orçamento de 1% da janela de contexto. Rode
/doctorpra ver o custo e desative as que você não usa. - [ ] No Windows, o
!não roda. O padrão é bash. Comshell: powershellno frontmatter e a ferramenta PowerShell ativa, os comandos injetados rodam pelo PowerShell (veja Claude Code no Windows).
Perguntas frequentes
Qual a diferença entre skill e comando (.claude/commands)?▼
Nenhuma pra invocar: .claude/commands/deploy.md e .claude/skills/deploy/SKILL.md criam o mesmo /deploy. A skill ganha pasta pra arquivos de apoio e o disparo automático.
Skill funciona fora do Claude Code?▼
O formato segue o padrão Agent Skills. Mas pra subir no claude.ai ou na API de Skills, só seis campos de frontmatter são aceitos (name, description, license, compatibility, metadata, allowed-tools), e recursos como a injeção com ! não funcionam lá.
Skill ou MCP?▼
MCP quando é preciso conectar num sistema; skill quando é preciso ensinar um procedimento. Muitas vezes, os dois juntos.
Uma skill de projeto pode ser perigosa?▼
Pode. O allowed-tools de uma skill de projeto vale até em pasta que você nunca marcou como confiável. Revise as skills de um repositório antes de rodar o Claude Code nele.
Leia também
- Claude Code é um harness: CLAUDE.md, hooks, MCP e subagentes (o guia principal)
- Como escrever um CLAUDE.md que o agente segue
- Como configurar hooks no Claude Code
- Como criar um servidor MCP em Python e configurar no Claude Code
- Como instalar o Claude Code no Windows
Quer um fluxo inteiro de skills, hooks e gates pronto pro seu time? Conheça o capivaOS.