Criando Skills
Guia passo a passo para adicionar novas capacidades ao seu projeto Arc OS.
Antes de escrever uma nova skill — confira a biblioteca global
O Arc OS já vem com 40+ skills genéricas em skills/ cobrindo roles comuns. Antes de criar uma nova, veja se alguma existente atende à sua necessidade:
| Domínio | Skills disponíveis |
|---|---|
| Engineering | commit-discipline, tdd-flow, react-best-practices, postgres-patterns, mcp-builder |
| Frontend / Design | frontend-design-principles, svg-graphics, slide-deck-html, service-design, scss-modular-architecture, responsive-mobile-first |
| Startup ops | market-analysis, gtm-strategy, financial-modeling, pitch-deck, customer-development, fundraising, founder-brand, metrics-dashboard, legal-startup |
| Marketing | seo-foundations, founder-brand |
| Process | standup-aggregator, commit-discipline |
| Database | postgres-patterns |
Veja a lista completa: GET /api/crm/skills?category=<X> ou bun -e "console.log(JSON.stringify(require('./skills/_registry.json').skills.map(s=>s.name),null,2))".
Skill = ativada por trigger, não always-on
A skill é injetada automaticamente no prompt do worker quando a mensagem corresponde aos seus triggers (no _registry.json). O campo description é lógica de trigger ("quando usar isto"), não um resumo. O Context Router escolhe os top-5 matches por mensagem.
O Que É uma Skill
Uma skill é um conjunto portátil de instruções que ensina ao seu bot de IA uma capacidade específica. As skills ficam no diretório skills/ e são compostas por:
<name>.md— o arquivo de instruções (obrigatório)<name>.evals.json— regras de validação automática de qualidade (opcional, mas recomendado)references/— documentos de apoio, schemas, exemplos (opcional)
skills/
├── _registry.json ← Central registry
├── my-new-skill/
│ ├── skill.md ← What the AI should do
│ ├── my-new-skill.evals.json ← How to validate the output
│ └── references/ ← Context documents
└── library/
└── domain-expert.md ← Simple single-file skills
Passo 1: Escreva o skill.md
Este é o núcleo da instrução. Claude lê este arquivo quando a skill é ativada.
Template
# Skill Name
## Purpose
What this skill accomplishes in one sentence.
## When to Use
- Trigger condition 1
- Trigger condition 2
## Protocol
1. First action
2. Second action
3. Third action
## Output Format
What the response should look like.
## Constraints
- What NOT to do
- Safety boundaries
Diretrizes
- Menos de 500 palavras — skills mais longas diluem o contexto
- Modo imperativo — "Verifique o repositório", não "Você deveria verificar"
- Exemplos concretos — mostre pares esperados de entrada/saída
- Referências específicas de ferramentas — mencione os comandos, APIs ou padrões a usar
Exemplo: Odoo Expert
# Odoo Expert
## Purpose
Odoo ERP module development: models, views, security, QWeb templates.
## When to Use
- Building or modifying Odoo modules
- Writing QWeb templates
- Configuring access rules and record rules
- Working with the ORM (create, write, search, browse)
## Protocol
1. Check if modifying an existing module or creating new
2. Follow Odoo 17 conventions (manifest, models/, views/, security/)
3. Use self.env['model.name'] for ORM operations
4. Always use _t() or t-call for translatable strings
5. Test with --test-tags after changes
## Constraints
- Never use cr.execute() for direct SQL — use ORM
- Never use sudo() unless security context explicitly requires it
- No inline JavaScript in QWeb templates
Passo 2: Escreva os Evals (Regras de Qualidade)
Evals são regras declarativas que validam automaticamente cada resposta. Eles rodam depois que Claude gera o output e adicionam notas de aviso caso alguma regra falhe.
Nomenclatura do arquivo
skills/<name>/<name>.evals.json
Schema
{
"version": 1,
"skill": "my-new-skill",
"rules": [
{
"id": "ms-001",
"name": "Human-readable rule description",
"type": "rule_type",
"value": "for string/length types",
"pattern": "for regex types",
"severity": "warning"
}
]
}
Tipos de Regra Disponíveis
| Tipo | O Que Verifica | Campo Usado |
|---|---|---|
string_contains |
A resposta inclui o texto literal | value (string) |
string_not_contains |
A resposta NÃO inclui o texto | value (string) |
regex_match |
A resposta corresponde ao regex | pattern (string) |
regex_not_match |
A resposta NÃO corresponde ao regex | pattern (string) |
max_length |
Tamanho da resposta <= N caracteres | value (number) |
min_length |
Tamanho da resposta >= N caracteres | value (number) |
Níveis de Severidade
warning— Indica um problema de qualidade. Exibido como⚠️.info— Nota informativa. Exibido comoℹ️.
Exemplo
{
"version": 1,
"skill": "odoo-expert",
"rules": [
{
"id": "oe-001",
"name": "Must use ORM, not raw SQL",
"type": "string_not_contains",
"value": "cr.execute",
"severity": "warning"
},
{
"id": "oe-002",
"name": "Must use translation helpers",
"type": "regex_match",
"pattern": "_t\\(|t-call|t-esc",
"severity": "warning"
},
{
"id": "oe-003",
"name": "Response under 5000 chars",
"type": "max_length",
"value": 5000,
"severity": "info"
}
]
}
Dicas
- Comece com 2-3 regras. Adicione mais conforme identificar padrões nas correções.
- Segurança em primeiro lugar:
string_not_containspara comandos perigosos,regex_not_matchpara padrões de credenciais. - Convenção de ID:
<prefixo-da-skill>-<número>(ex.:oe-001,gm-002). - Teste: Envie uma mensagem que deveria ativar a skill e verifique se os avisos aparecem corretamente.
Passo 3: Registre em _registry.json
O registry informa ao Context Router sobre sua skill para que ela possa ser recomendada em mensagens relevantes.
Adicione uma entrada
{
"name": "my-new-skill",
"description": "One sentence (shown in SKILLS_HINT, max 80 chars).",
"triggers": ["direct-command", "explicit-request", "пряма команда"],
"keywords": ["broader", "semantic", "related-term"],
"agents": ["rick"],
"category": ["complex"],
"phase": "21.5"
}
Triggers vs Keywords
Triggers (2 pontos cada): Sinais de invocação direta. O usuário quer explicitamente esta skill.
- "deploy", "review", "scaffold", "odoo", "audit"
Keywords (1 ponto cada): Termos mais amplos que sugerem relevância sem serem comandos diretos.
- "OWASP", "Docker", "CI/CD", "production", "module"
Diretrizes
- Inclua equivalentes em ucraniano nos triggers para times bilíngues
- Mantenha as descrições com menos de 80 caracteres (truncado no SKILLS_HINT)
- 5-8 triggers por skill (mais = correspondências ruidosas)
- Keywords são opcionais, mas melhoram significativamente o roteamento
Passo 4: Library Skills (Formato Simples)
Para expertise de domínio que não precisa de evals ou de um diretório dedicado, use skills/library/:
skills/library/
├── docker-ops.md
├── postgres-pro.md
└── react-patterns.md
São arquivos .md individuais. Sem diretório, sem evals, sem referências. Ideal para skills com muito conhecimento e pouca necessidade de validação.
Checklist
-
skills/<name>/skill.md— instrução com Purpose, Protocol, Constraints -
skills/<name>/<name>.evals.json— pelo menos 2 regras de validação - Entrada em
skills/_registry.json— com triggers e keywords - Nome idêntico em todos os lugares — nome do diretório = nome da skill no eval = nome no registry
- Teste: envie uma mensagem de trigger → verifique o SKILLS_HINT nos logs
- Teste: provoque intencionalmente uma falha de eval → verifique se o aviso aparece
O Que Acontece em Tempo de Execução
1. Bot starts → loadRegistry() reads _registry.json
loadEvals() reads all .evals.json files
loadLearnings() reads learnings.md
2. Message arrives → routeContext() scores skills → SKILLS_HINT injected
formatForPrompt() adds LEARNINGS block
3. Claude responds → checkOutput() runs eval rules
formatEvalWarnings() appends footnotes
4. Fix It / thumbs-down → addLearning() writes to learnings.md
qualityTracker logs feedback
5. Nightly → findUnderperformingSkills() checks metrics
Proposals sent to CEO for approval
Semeando skills no DB global
As skills no DB (tabela skills_global) são o SSOT do Context Router. O arquivo em disco é a fonte da verdade do conteúdo; o DB é o índice rápido para matching + auto-injeção. Eles sincronizam via scripts de seed.
Seeder genérico por categoria
# Reads skills/_registry.json, filters by category, upserts skills_global rows.
# Idempotent + drift-aware (skip if no change, update on content drift).
bun scripts/seed-skill-category.ts --category engineering
bun scripts/seed-skill-category.ts --category frontend
bun scripts/seed-skill-category.ts --category marketing
Funciona para qualquer categoria presente no _registry.json. Usa a primeira categoria do array como valor da coluna no DB.
Seeders específicos
scripts/seed-startup-skills.ts— hardcoded para category="startup" (10 skills de operações de startup)scripts/migrate-skills-to-db.ts— migração histórica em massa (todos os arquivos, apenas insert, sem update)
Quando executar
- Após criar um novo
.md+ entrada no_registry.json→ rode o seeder uma vez - Após atualizar o conteúdo de um
.mdexistente → o seeder drift-aware atualiza o DB - Bootstrap de novo projeto → seeders rodam via
vps-sync.shStep 1.5 (planejado)
Verificando
sqlite3 data/citadel.db "SELECT name, category, owner_project FROM skills_global ORDER BY id"
owner_project = NULL → global (todos os projetos enxergam). owner_project = 'my-project' → apenas do projeto (somente aquele projeto).
Skills project-only vs globais
| Tipo de skill | owner_project |
Caso de uso |
|---|---|---|
| Global (template) | NULL | Metodologia genérica (TDD, Conventional Commits, AARRR) — útil para qualquer projeto |
| Project-only | '<project-name>' |
Documenta especificidades do NOSSO codebase (p.ex. crm-api-reference existe só no arc-v2) |
Mover uma skill existente para project-only:
sqlite3 data/citadel.db "UPDATE skills_global SET owner_project='my-project' WHERE name='internal-api-docs'"
O filtro listForProject controla a visibilidade: outros projetos não verão uma skill project-only.