Disequei o OpenCode para provar que você não entende NADA de SKILLS
Outro dia vi alguém num grupo perguntando “como eu crio uma skill pro Claude Code?”, e as respostas eram do tipo “usa esse template”, “instala esse pacote”, “segue esse guia de 20 passos”. Falam de skills como se fosse algo mágico, um recurso avançado que exige conhecimento especial.
Não exige. E pra te convencer disso, fui olhar o código-fonte do OpenCode pra ver o que realmente acontece por baixo dos panos.
Mas antes, preciso te explicar como LLMs funcionam de verdade. Sem isso, skill não faz sentido.
LLMs não fazem nada
Um LLM é uma função. Entra texto, sai texto. Ele não acessa a internet, não lê arquivos, não executa código. Ele prevê o próximo token baseado no que recebeu.
Isso é literalmente tudo.
Quando você manda uma mensagem pro Claude ou pro GPT e ele “lê um arquivo” ou “busca na web”, não é o modelo fazendo isso. É o sistema ao redor dele. O modelo só gera texto. Quem age é o programa que orquestra a conversa.
Tools: dando mãos ao modelo
Pra que um LLM interaja com o mundo real, usamos tools (ou function calling). O fluxo é:
- Você envia uma mensagem junto com uma lista de tools disponíveis - cada uma com nome, descrição e parâmetros
- O modelo analisa a mensagem e decide se precisa usar alguma tool
- Se sim, ele responde pedindo a execução:
{ "tool": "read_file", "args": { "path": "src/main.ts" } } - O sistema host (não o modelo) executa a tool e devolve o resultado
- O modelo recebe o resultado e continua gerando a resposta
O modelo nunca executa nada. Ele apenas pede pra executar. Quem roda é o agente.
Agentes: o loop que conecta tudo
Um agente é esse loop. Simplificando ao máximo:
enquanto não terminou:
resposta = llm.gerar(mensagens, tools)
se resposta tem tool_call:
resultado = executar(tool_call)
mensagens.append(resultado)
senão:
retornar resposta
O agente mantém o histórico, injeta as definições de tools, executa as chamadas e alimenta o modelo com os resultados. O OpenCode faz exatamente isso em packages/opencode/src/session/prompt.ts.
Se você quer entender agentes de verdade, estuda esse loop. Todo o resto é detalhe de implementação.
Como o OpenCode registra tools
No OpenCode, toda tool implementa uma interface Tool.Info definida em packages/opencode/src/tool/tool.ts:
export interface Info<Parameters, M> {
id: string
init: (ctx?) => Promise<{
description: string
parameters: Parameters
execute(args, ctx): Promise<{ title, metadata, output }>
}>
}
Toda tool tem um id, uma description, os parameters que aceita e uma função execute. O ToolRegistry em packages/opencode/src/tool/registry.ts junta todas - built-in, custom e de plugins - e entrega pro modelo a cada interação.
As tools built-in são registradas assim:
return [
ReadTool, GlobTool, GrepTool, EditTool, WriteTool,
BashTool, TaskTool, WebFetchTool, SkillTool,
// ...
]
Repara nesse SkillTool ali no meio. Guarda esse nome.
Agora sim: o que é uma skill?
Uma skill no OpenCode é um arquivo markdown chamado SKILL.md com um frontmatter YAML:
---
name: agents-sdk
description: Build AI agents on Cloudflare Workers using the Agents SDK
---
# Cloudflare Agents SDK
Aqui vão instruções detalhadas, exemplos de código,
referências, boas práticas...
Isso. Um arquivo .md com nome e descrição.
O código que descobre esses arquivos está em packages/opencode/src/skill/skill.ts. Ele varre SKILL.md em diretórios globais (~/.claude/skills/, ~/.agents/skills/), diretórios do projeto (.opencode/skills/), caminhos custom e até URLs remotas.
O truque: SkillTool é só uma tool
O SkillTool em packages/opencode/src/tool/skill.ts é uma tool como qualquer outra. Na sua função init(), ele:
- Escaneia todos os
SKILL.mddisponíveis - Monta sua própria descrição listando o que encontrou:
<available_skills>
<skill>
<name>agents-sdk</name>
<description>Build AI agents on Cloudflare Workers...</description>
</skill>
</available_skills>
Essa descrição vai pro modelo junto com as outras tools. Quando o modelo decide que precisa de uma skill, faz uma chamada de tool normal:
{ "tool": "skill", "args": { "name": "agents-sdk" } }
O SkillTool recebe essa chamada, lê o SKILL.md correspondente e devolve o conteúdo. O modelo usa essas instruções pra continuar o trabalho.
Releia. É o mesmo fluxo de qualquer tool. O modelo pede, o sistema lê um arquivo, o conteúdo volta pro contexto.
Pensa assim: se o modelo pode chamar read_file pra ler um arquivo de código, por que não pode chamar uma tool pra ler um arquivo de instruções? É exatamente isso que a SkillTool faz. A diferença é só a convenção - um lugar padronizado pra colocar instruções reutilizáveis que o modelo puxa sob demanda.
Como criar uma skill, de verdade
- Cria uma pasta dentro de
.opencode/skills/(ou.claude/skills/, dependendo do agente) - Coloca um
SKILL.mddentro com frontmatternameedescription - Escreve as instruções em markdown
Pronto. Não tem passo 4.
O modelo vai ver a descrição curta da sua skill na lista de tools disponíveis. Se ele achar relevante pro que está fazendo, vai chamar a tool e ler o conteúdo completo. Se não achar, ignora. Você não força nada.
O conteúdo completo só entra no contexto quando o modelo pede. As descrições são leves, o markdown pesado fica de fora até ser necessário.
Uma dica sobre o que colocar numa skill: o Sean Goedecke escreveu sobre gerar skills depois de resolver o problema, não antes. A ideia é que a LLM escreve skills melhores depois que ela já iterou na solução, porque daí ela destila o que aprendeu. Faz sentido - você não escreve documentação boa antes de entender o problema.
Conclusão
Skill é um arquivo markdown que uma tool lê quando o modelo pede. O mesmo tool calling que permite o modelo ler arquivos ou executar comandos é o que permite ele carregar uma skill. Não tem framework, não tem runtime, não tem mágica.
Se você sabe escrever markdown, você sabe criar skills.
Por hoje é só.