Blog · AI Harness

Como criar uma Skill no Claude Code: SKILL.md passo a passo, com script e argumentos

Capiva · Outubro 2026 · 9 min de leitura

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údoOnde 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/scripts

Onde a pasta fica decide quem vê a skill:

LocalCaminhoVale para
Pessoal~/.claude/skills/<nome>/SKILL.mdVocê, em todos os projetos
Projeto.claude/skills/<nome>/SKILL.mdTodo mundo no repositório (vai pro git)
Plugin<plugin>/skills/<nome>/SKILL.mdQuem 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 e when_to_use juntas são cortadas em 1.536 caracteres na listagem.
  • argument-hint aparece no autocomplete. O que vier depois de /nova-adr substitui $ARGUMENTS no 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 do allowed-tools.
  • allowed-tools libera 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: 0015

Valide 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 passed

Com 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 failed

Vale 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 Redis

Antes 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), description vaga, ou disable-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 em allowed-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 /doctor pra ver o custo e desative as que você não usa.
  • [ ] No Windows, o ! não roda. O padrão é bash. Com shell: powershell no 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

Quer um fluxo inteiro de skills, hooks e gates pronto pro seu time? Conheça o capivaOS.