Escrever custom skills: templates que continuam seguros
A compilação de um skill numa entrada de contexto destacada: whitelist, passagem única, escopo em três níveis, DLP antes de compilar e o freemium max_skills (3 ou ilimitado).

Instruções que se chamam, não código em que é preciso confiar
Um custom skill é um template de prompt reutilizável: escrito uma vez, invocado do chat como comando slash às vezes que fizerem falta. A aposta de projeto está na frase "template de prompt": um skill não contém chamadas HTTP, nem I/O de arquivos, nem lógica condicional, nem sandbox - não há por onde fugir, então a função é air-gap-safe por construção. O que um skill contém é um pipeline de compilação fixo com fronteiras reais: parâmetros em whitelist contra um schema, uma única passagem de substituição, máscara antes de compilar, e uma injeção que chega como dado não confiável.
Este artigo percorre o caminho de escrita de ponta a ponta: como um template se escreve e se compila, a gramática do comando slash, os três níveis de escopo, a fronteira de privilégio que mantém honesta a saída compilada, e a forma de licença (max_skills - 3 na Community, ilimitado na Enterprise).
O template e suas regras
Um template é uma string simples com placeholders {{param}}:
Translate to {{targetLang}}: {{input}}O pipeline de compilação impõe quatro regras (cravadas no schema):
- Whitelist - só as chaves declaradas no
inputSchema.propertiesdo skill (mais os seus parâmetros padrão) substituem. Um placeholder desconhecido permanece literal na saída - nunca resolvido do ambiente, do contexto de sistema, ou qualquer outra coisa. - Passagem única - roda exatamente uma passagem de substituição. Um valor substituído que contém formas de marcador
{...}dentro de si nunca se re-expande; a injeção via template morre aqui no nível estrutural. - Coerência - cada placeholder do template precisa da sua entrada no input-schema; create/patch sem = um 400 nomeado.
- Rejeição de marcadores - o texto estático do template (sem os placeholders) não pode carregar formas de marcadores de tool-call entre provedores; rejeitadas no create/patch. Os valores dos parâmetros levam a sua própria defesa mais abaixo.
A gramática do comando slash
Digitar / abre a paleta de skills (o autocomplete); uma linha escolhida insere o seu slug sem enviar. Ao enviar, o cliente interpreta os argumentos e manda a chamada junto com a mensagem digitada:
- Posicional:
/translate Ciao mondo- os tokens se fundem no primeiro campo requerido. - Pares:
/translate input=Ciao- preenchimentos nomeados; os trechos entre aspas (input="Ciao mondo") levam espaços. - Misto e padrões:
input="Ciao" targetLang=Spanish, ou uma chave requerida que toma o seu padrão declarado.
Dois comportamentos tornam a gramática digna de confiança em vez de esperta:
- A regra nunca-erro - uma
/palavrasem correspondência, um nome builtin ou uma linha desativada escorrega para uma mensagem normal: sem chamada, sem erro, sem nada escondido. - O servidor revalida tudo - chaves desconhecidas se ignoram; o slug se resolve de novo no servidor com o mesmo filtro de escopo a cada invocação (a guarda IDOR).
A lista de slugs reservados (os comandos fixos do chat + os nomes dos builtin) torna impossível a sombra: um skill custom nunca pode tomar um nome reservado.
O caminho do pedido: resolver, mascarar, compilar, embrulhar
"/slug params" → POST chat stream { message, skillCall }
→ resolveInvocableSkill (no servidor, filtrado por escopo)
→ máscara DLP ANTES de compilar (os valores se escaneiam quando o DLP está ativo)
→ compileTemplate (substituição em whitelist, uma passagem) + o invólucro spotlight
→ UMA entrada de contexto de usuário destacada no orquestradorA ordem com o DLP é o detalhe que carrega o peso: os parâmetros se mascaram antes da compilação. Compilados na ordem inversa, um texto escrito no template poderia esconder um parâmetro do escaneador; com esta ordem, o prompt compilado só leva valores mascarados. (O pipeline DLP em si - as máscaras numeradas, os originais cifrados, o unmask do admin - é sua própria história.)
A fronteira de privilégio
A saída compilada de um template é dado fornecido pelo usuário, não instruções. Entra na conversa como uma entrada de contexto destacada - etiquetada, contada no orçamento como qualquer outro tool result, e pregada por um teste de privilégio: um skill custom pode acrescentar contexto mas nunca pode acrescentar tools, permissões, ou entradas de registro. A transcrição guarda a mensagem digitada; só o prompt compilado entra como contexto do skill.
Por isso "sem sandbox" é uma característica e não uma limitação: a superfície de poder do template - o que pode influenciar - é exatamente uma entrada de contexto, e nada mais.
Escopo: três níveis, derivados no servidor
- Pessoal - só o autor o resolve (qualquer usuário com a permissão de criar).
- Workspace - quem quer que converse naquele workspace (criado por editor+; um viewer recebe um 403 explícito). A linha guardada carrega um user id nulo - uma linha estampada pelo criador vazaría entre workspaces, e o schema fecha essa classe.
- Global - todos na organização (criado só por admins).
O escopo reivindicado pelo cliente nunca é de confiança: o servidor deriva o nível da forma guardada e filtra a resolução por conversa. Edições e apagamentos valem a partir da próxima conversa - sem hooks, sem reinícios. O delete é um túmulo suave, e o slug se libera na hora: o nome de um skill apagado pode ser recriado imediatamente.
O fato freemium: max_skills
O limite de licença espelha as outras barreiras numéricas da plataforma: 3 skills personalizados na Community, ilimitado na Enterprise - a linha do census F-SKILL-1, fundamentada nas constantes de licença:
- Imposto só no CREATE - colocar barreiras nas invocações interromperia a conversa no meio por um motivo de licença, um projeto rejeitado; a contagem vive no provisionamento.
- A contagem é organizacional sobre as linhas custom - os builtin e as linhas do marketplace nunca contam.
- Acima do limite, a forma de paywall padrão nomeia a função e o tier - e a saída é de autoatendimento: cada usuário pode apagar os seus próprios skills para liberar cota, sem intervenção do admin.
Essa última propriedade é o contrato freemium feito honestamente: o limite é visível na UI de gestão, o 402 se explica sozinho, e a saída não custa ticket de suporte.
Para continuar
A guia leva a referência completa do operador - endpoints, a janela do formulário, a semântica da test-preview - em /pt/docs/custom-skills:
- Custom skills - a guia
- Fatos deste post: linhas
FACT-CENSUS.mdF-SKILL-1 (os skills personalizados + o freemiummax_skills) e F-DLP-1 (a camada de máscara que este caminho atravessa)
Provenance: Simmetric Chat docs/CUSTOM_SKILLS.md (v0.28.1, Phase 190 SKIL-01..05), packages/shared/src/schemas/skill.schema.ts, license.ts (max_skills) - no estado documental fixado pelo census (SHA aca5b8ff).
