Blog
Tutoriais

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).

Simmetric Team8 min de leitura12/10/2026
Escrever custom skills: templates que continuam seguros

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}}:

text
Translate to {{targetLang}}: {{input}}

O pipeline de compilação impõe quatro regras (cravadas no schema):

  • Whitelist - só as chaves declaradas no inputSchema.properties do 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 /palavra sem 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

text
"/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 orquestrador

A 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.md F-SKILL-1 (os skills personalizados + o freemium max_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).

Artigos relacionados