Pular para o conteúdo
IA

Criando uma Skill para IAs usarem a sua API

Ilustração de um unicórnio de crina arco-íris entregando um pergaminho com diagramas, um cadeado e um envelope para uma coruja robótica de olhos brilhantes, diante de um castelo-biblioteca com velas flutuantes

Olá meus Unicórnios! 🦄✨

Sabe aquele momento em que você pede uma coisa simples para a IA, ela responde lindamente, e você percebe que ela inventou o endereço do seu endpoint? 😅 Pois é. Ela não tinha como saber. A sua API é sua, mora na sua casa, e nunca apareceu em lugar nenhum que a IA tenha lido.

A solução não é explicar tudo de novo a cada conversa. É escrever uma vez um manual que ela abre sozinha quando o assunto aparece. Esse manual tem nome: é uma skill.

E a melhor parte: não tem código, não tem build, não tem servidor. É uma pasta com um arquivo de texto dentro. 🤯

📁 O que é uma skill, na prática

Uma skill é uma pasta com um arquivo chamado SKILL.md. Ponto. Se você criar a pasta e o arquivo, você já tem uma skill.

A estrutura mínima é esta:

entregas-api/
└── SKILL.md

E o arquivo é Markdown comum, com um cabeçalho especial no topo. Esse cabeçalho se chama frontmatter: são as linhas entre dois ---, escritas em YAML, e é ali que moram os dois únicos campos obrigatórios.

---
name: entregas-api
description: Consulta o status de entregas na API de Entregas. Use quando pedirem para rastrear entrega, ver onde está um pacote, consultar código de rastreio (formato BR seguido de 9 dígitos) ou saber se um pedido já foi entregue.
---

# API de Entregas

Documentação para consultar entregas pela API HTTP.

É só isso mesmo. A partir daqui, tudo o que vamos fazer é escrever bem esses dois campos e o texto que vem embaixo deles. 🙂

🎯 A description é tudo, e é onde quase todo mundo erra

Se você só for ler um pedaço deste artigo, leia este. 🙏

A IA não lê a sua skill inteira o tempo todo. Seria caro e lento ter dezenas de manuais abertos em toda conversa. O que ela enxerga, sempre, é apenas o name e a description. Com esses dois pedacinhos de texto ela decide: abro este manual ou não?

Ou seja: a description não é um resumo bonito. Ela é o gatilho. E gatilho que não bate com o que a pessoa digitou não dispara.

Repare na diferença cruel entre estas duas. A primeira:

description: Documentação da API de Entregas.

Essa aí nunca vai ser aberta. Ninguém digita "documentação da API de Entregas" no chat. A pessoa digita "onde está a minha encomenda BR123456789". Agora compare:

description: Consulta o status de entregas na API de Entregas. Use quando
  pedirem para rastrear entrega, ver onde está um pacote, consultar código de
  rastreio (formato BR seguido de 9 dígitos) ou saber se um pedido já foi
  entregue.

Essa segunda tem as palavras que a pessoa realmente usa: rastrear, pacote, encomenda, código de rastreio, entregue. E tem o formato do código, que é um sinal fortíssimo: quando a IA vê BR123456789 na frase, casa na hora.

A receita que funciona é sempre a mesma:

  1. O que a skill faz, numa frase.
  2. "Use quando…" seguido dos termos reais que disparam o assunto.
  3. Um formato reconhecível, se a sua API tiver um (código, prefixo, número de documento).

O teste é fácil: escreva a frase que você digitaria num dia normal de trabalho. Se nenhuma palavra dela aparece na sua description, a skill está invisível. 😬

📖 O corpo: a documentação que a IA vai seguir

Passado o gatilho, vem o manual. E aqui a regra muda: agora a IA vai ler tudo, então escreva para quem não conhece nada da sua API.

Um corpo que funciona tem quatro partes: o endereço-base, a autenticação, os endpoints com exemplo de chamada, e a tabela de erros. Vamos por partes.

Primeiro o básico, que responde "para onde eu mando e como eu me identifico":

## Endereço-base

    https://api.exemplo.com.br/v1

## Autenticação

Toda chamada precisa do cabeçalho `X-API-Key` com a chave da conta.

A chave fica na variável de ambiente `ENTREGAS_API_KEY`. Nunca escreva o
valor dela em arquivo nem repita a chave na resposta ao usuário.

Repare na última frase. Ela parece desnecessária e não é: sem ela, a IA às vezes ecoa a chave no meio de uma explicação. Instrução explícita de não fazer algo vale tanto quanto a de fazer. 🔐

🧪 Exemplo de chamada: o pedaço que a IA copia

Agora o coração da skill. Para cada endpoint, dê um exemplo completo que roda copiando e colando, e logo abaixo a resposta de verdade.

## Consultar uma entrega

    GET /v1/entregas?codigo=BR123456789

Exemplo:

```bash
curl -s -H "X-API-Key: $ENTREGAS_API_KEY" \
  "https://api.exemplo.com.br/v1/entregas?codigo=BR123456789"
```

Resposta:

```json
{
    "codigo": "BR123456789",
    "situacao": "em_transito",
    "cidade": "Curitiba"
}
```

O campo `situacao` só assume três valores: `postado`, `em_transito`
e `entregue`. Qualquer outro valor é erro de leitura, não situação nova.

Três detalhes desse bloco que valem ouro, e que a maioria das documentações esquece:

  • O exemplo usa a variável de ambiente ($ENTREGAS_API_KEY), não uma chave escrita. Assim a IA copia o padrão certo, e não o errado.
  • A resposta está formatada, em linhas. JSON grudado numa linha só a IA até lê, mas ela aprende a estrutura muito melhor assim, e você também.
  • Os valores possíveis estão listados. Sem essa linha, a IA vê em_transito uma vez e assume que existe atrasado, extraviado e o que mais a imaginação der. Enumerar corta a invenção pela raiz.

🚨 A tabela de erros, que ninguém escreve e todo mundo precisa

Essa é a seção que separa uma skill que funciona de uma que funciona só quando dá tudo certo.

Sem a tabela de erros, a IA acerta o caminho feliz e trava no primeiro tropeço, inventando explicação para um número que ela não conhece. Com a tabela, ela sabe o que fazer:

## Erros

| Código | O que aconteceu | O que fazer |
|---|---|---|
| 401 | Chave ausente ou inválida | Conferir a variável `ENTREGAS_API_KEY` |
| 404 | Código de rastreio não existe | Avisar o usuário, não tentar de novo |
| 429 | Passou de 60 consultas por minuto | Esperar 60 segundos e repetir uma vez |
| 500 | Falha na API | Repetir uma vez; se persistir, avisar |

Olhe a coluna da direita com carinho. "O que fazer" é o que evita os dois desastres clássicos: repetir para sempre um erro que nunca vai mudar (o 404) e desistir na primeira de um erro passageiro (o 500). Sem essa coluna, a IA escolhe no chute, e o chute vem caro quando a sua API cobra por chamada. 💸

💻 Quando a API não cabe num curl

Consulta simples resolve com curl. Mas às vezes é preciso tratar o resultado, e aí vale colocar um script pronto na skill.

Este é o consultador completo, num arquivo só, de cima para baixo:

// Consulta uma entrega na API de exemplo.
// Uso: node consultar.js BR123456789

async function consultarEntrega(codigo) {
    const chave = process.env.ENTREGAS_API_KEY;   // a chave nunca fica escrita no arquivo
    if (!chave) {
        throw new Error("Falta a variavel de ambiente ENTREGAS_API_KEY.");
    }

    const endereco = "https://api.exemplo.com.br/v1/entregas?codigo=" + encodeURIComponent(codigo);

    const resposta = await fetch(endereco, {
        headers: { "X-API-Key": chave }
    });

    // Sem esta checagem o erro chega como JSON e o programa segue achando que deu certo.
    if (!resposta.ok) {
        const corpo = await resposta.text();
        throw new Error("A API respondeu " + resposta.status + ": " + corpo);
    }

    return await resposta.json();
}

async function main() {
    const codigo = process.argv[2];
    if (!codigo) {
        console.log("Uso: node consultar.js <codigo>");
        return;
    }

    try {
        const entrega = await consultarEntrega(codigo);
        console.log("Situacao:", entrega.situacao);
        console.log("Cidade:  ", entrega.cidade);
    } catch (erro) {
        console.error("Nao deu para consultar:", erro.message);
    }
}

main();

Duas linhas desse arquivo merecem atenção, porque cada uma evita um bug específico.

O if (!resposta.ok) é a mais importante. O fetch não lança erro quando a API responde 401 ou 404: para ele, a resposta chegou, missão cumprida. Sem essa checagem o programa segue em frente, faz resposta.json() num corpo de erro, e imprime Situacao: undefined com ar de quem deu certo. É o pior tipo de bug, porque não parece bug.

O encodeURIComponent é o outro. Ele existe para o caso de o código vir com espaço, acento ou & no meio: sem ele, a URL quebra e a API recebe outra coisa.

E veja a saída, com o servidor no ar e a chave no lugar:

$ node consultar.js BR123456789
Situacao: em_transito
Cidade:   Curitiba

$ node consultar.js BR000000000
Nao deu para consultar: A API respondeu 404: {"erro":"entrega nao encontrada"}

$ ENTREGAS_API_KEY=errada node consultar.js BR123456789
Nao deu para consultar: A API respondeu 401: {"erro":"chave ausente ou invalida"}

Repare que os dois caminhos de erro dizem exatamente o que houve, com o código e o corpo da resposta. É isso que a IA vai ler quando rodar o script, e é por isso que a mensagem de erro precisa ser boa: ela é o que a IA usa para decidir o próximo passo. Mensagem vaga ("erro ao consultar") deixa a IA no escuro igual a você. 🔦

Com o script na pasta, a skill fica assim, e o SKILL.md ganha uma linha dizendo que ele existe:

entregas-api/
├── SKILL.md
└── consultar.js

📚 Quando a documentação não cabe num arquivo só

API pequena cabe inteira no SKILL.md. Mas se a sua tem trinta endpoints, colocar tudo lá é um tiro no pé: a IA carrega o manual inteiro para consultar um código de rastreio.

O padrão então é separar. No SKILL.md ficam os dois ou três endpoints do dia a dia, e o resto vai para arquivos citados pelo caminho:

entregas-api/
├── SKILL.md
├── consultar.js
└── referencia/
    ├── endpoints-completos.md
    └── codigos-de-situacao.md

E no corpo do SKILL.md você só aponta:

## Mais endpoints

Os outros 28 endpoints (criação, cancelamento, etiquetas, relatórios)
estão em `referencia/endpoints-completos.md`. Leia esse arquivo quando
o pedido não for uma consulta simples de rastreio.

A frase "leia esse arquivo quando…" faz o trabalho todo: a IA abre o arquivo extra só quando precisa. É a mesma ideia da description, um nível abaixo. 🪆

🧯 Os erros que eu vejo em quase toda skill de API

Junte estes cinco e você já está à frente da maioria:

1. Description escrita como título de manual. Já falamos, mas é o campeão disparado. "Documentação da API X" não dispara nada.

2. A chave escrita dentro do SKILL.md. Tentador, porque funciona na hora. Só que a pasta da skill vai para o git, vai para o colega, vai para o backup. E chave publicada é chave queimada: trocar depois não apaga o que já subiu. O nome da variável entra; o valor, nunca.

3. Nenhum exemplo de resposta. Só o endereço do endpoint. A IA tenta adivinhar os nomes dos campos e erra: seu JSON tem situacao, ela escreve status, e nada funciona.

4. Nenhuma tabela de erros. Funciona lindo até o dia em que não funciona.

5. Endereço de exemplo diferente do real. Documentação que ficou com localhost:3000 de quando você estava testando. A IA copia fielmente o que está escrito, e aí passa meia hora chamando um servidor que não existe na máquina dela. 🙃

✅ O roteiro inteiro, em cinco minutos

Juntando tudo, criar a skill é isto. Primeiro a pasta:

mkdir entregas-api

Crie o SKILL.md dentro dela, com o frontmatter de dois campos e, no corpo, nesta ordem: endereço-base, autenticação, um endpoint com curl e resposta formatada, e a tabela de erros. Se precisar de script, ponha o arquivo ao lado e cite-o no texto.

Depois teste do jeito mais honesto que existe: abra uma conversa nova e peça o que um usuário pediria, com as palavras dele. "Onde está a encomenda BR123456789?" Se a IA abrir a skill e acertar a chamada, você terminou. Se ela ignorar, o problema está na description, e é ali que você volta.

É bonito quando funciona: você escreve um arquivo de texto e a sua API, que era um segredo entre você e o servidor, passa a ser uma coisa que qualquer IA sabe usar. ✨

Por hoje é só, meus unicórnios! 🦄✨

Que a magia do arco-íris continue brilhando em suas vidas! Até mais! 🌈🌟

Perguntas frequentes

O que é exatamente uma skill?
É uma pasta com um arquivo SKILL.md dentro, e nada mais que isso precisa existir. O arquivo começa com um frontmatter YAML de dois campos (name e description) e continua em Markdown comum. Não tem build, não tem instalação, não tem servidor rodando: é documentação em pasta.
Por que a minha skill nunca é usada pela IA?
Quase sempre é a description. Ela é o único texto que a IA lê antes de decidir abrir a skill, e se estiver escrita como título de manual ("Documentação da API interna") não bate com nada que a pessoa digita. Escreva as palavras reais: "rastrear entrega", "código de rastreio", "status do pedido", "BR123456789".
Qual a diferença entre uma skill e um servidor MCP?
O MCP é código rodando: um servidor que expõe ferramentas e executa chamadas. A skill é texto: ela ensina a IA a usar as ferramentas que ela já tem, como o terminal. Para uma API HTTP que já responde a curl, a skill resolve sem você manter processo nenhum de pé.
Posso colocar a chave da API dentro do SKILL.md?
Não. Todo mundo que recebe a pasta recebe a chave junto, e ela vai para o histórico do git na primeira vez que você commitar. Escreva no SKILL.md o nome da variável de ambiente e como obter a chave; o valor fica fora, na máquina de quem usa.
Preciso quebrar a skill em vários arquivos?
Só quando o SKILL.md passar de umas 500 linhas. Aí o padrão é deixar no arquivo principal os dois ou três endpoints do dia a dia e mandar o resto para referencia/, citando o caminho no texto. A IA lê o arquivo extra quando precisa, em vez de carregar tudo sempre.
O que mais falta numa skill de API?
A tabela de erros. Sem ela a IA acerta o caminho feliz e trava no primeiro 401, inventando explicação. Liste o código, o que significa na sua API e o que fazer: 401 é chave errada, 404 é código inexistente, 429 é limite por minuto e pede espera.
IA