Créer des skills
Guide pas à pas pour ajouter une nouvelle expertise à ton projet Arc OS.
Avant d'écrire un nouveau skill — consulte la bibliothèque globale
Arc OS est livré avec plus de 40 skills génériques dans skills/ couvrant les rôles courants. Avant d'en écrire un nouveau, vérifie si un existant couvre ton besoin :
| Domaine | Skills disponibles |
|---|---|
| Ingénierie | 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 |
| Ops de startup | 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 |
| Base de données | postgres-patterns |
Parcours la liste complète : 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 = déclenché par trigger, pas toujours actif
Un skill s'auto-injecte dans le prompt du worker quand le message correspond à ses triggers (dans _registry.json). Le champ description est la logique de trigger (« quand l'utiliser »), pas un résumé. Le Context Router choisit le top-5 des correspondances par message.
Qu'est-ce qu'un skill
Un skill est un jeu d'instructions portable qui enseigne une capacité spécifique à ton bot IA. Les skills vivent dans le répertoire skills/ et se composent de :
<name>.md— le fichier d'instructions (requis)<name>.evals.json— règles de validation automatique de qualité (optionnel mais recommandé)references/— documents de support, schémas, exemples (optionnel)
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
Étape 1 : Écris skill.md
C'est l'instruction principale. Claude la lit quand le skill est activé.
Modèle
# 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
Recommandations
- Moins de 500 mots — les skills plus longs diluent le contexte
- Mode impératif — « Vérifie le dépôt » et non « Tu devrais vérifier »
- Exemples concrets — montre des paires entrée/sortie attendues
- Références d'outils spécifiques — nomme les commandes, APIs ou patterns à utiliser
Exemple : 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
Étape 2 : Écris les evals (règles de qualité)
Les evals sont des règles déclaratives qui valident automatiquement chaque réponse. Elles s'exécutent après que Claude a généré sa sortie et ajoutent des notes d'avertissement si des règles échouent.
Nommage des fichiers
skills/<name>/<name>.evals.json
Schéma
{
"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"
}
]
}
Types de règles disponibles
| Type | Ce qu'il vérifie | Champ utilisé |
|---|---|---|
string_contains |
La réponse inclut un texte littéral | value (string) |
string_not_contains |
La réponse n'inclut PAS un texte | value (string) |
regex_match |
La réponse correspond à une regex | pattern (string) |
regex_not_match |
La réponse ne correspond PAS à une regex | pattern (string) |
max_length |
Longueur de la réponse <= N caractères | value (number) |
min_length |
Longueur de la réponse >= N caractères | value (number) |
Niveaux de sévérité
warning— Indique un problème de qualité. Affiché en⚠️.info— Note consultative. Affichée enℹ️.
Exemple
{
"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"
}
]
}
Astuces
- Commence avec 2-3 règles. Ajoute-en au fur et à mesure que tu découvres des patterns à partir des corrections.
- Sécurité d'abord :
string_not_containspour les commandes dangereuses,regex_not_matchpour les patterns d'identifiants. - Convention d'ID :
<skill-prefix>-<number>(ex.oe-001,gm-002). - Teste : Envoie un message qui devrait déclencher le skill, vérifie que les avertissements apparaissent correctement.
Étape 3 : Enregistre dans _registry.json
Le registry informe le Context Router de ton skill pour qu'il puisse être recommandé sur les messages pertinents.
Ajoute une entrée
{
"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 points chacun) : Signaux d'invocation directe. L'utilisateur veut explicitement ce skill.
- « deploy », « review », « scaffold », « odoo », « audit »
Keywords (1 point chacun) : Termes plus larges qui suggèrent la pertinence sans être des commandes.
- « OWASP », « Docker », « CI/CD », « production », « module »
Recommandations
- Inclus les équivalents ukrainiens dans les triggers pour les équipes bilingues
- Garde les descriptions sous 80 caractères (tronquées dans SKILLS_HINT)
- 5-8 triggers par skill (plus = matching bruyant)
- Les keywords sont optionnels mais améliorent significativement le routage
Étape 4 : Skills de bibliothèque (format simple)
Pour une expertise de domaine qui n'a pas besoin d'evals ni d'un répertoire dédié, utilise skills/library/ :
skills/library/
├── docker-ops.md
├── postgres-pro.md
└── react-patterns.md
Ce sont des fichiers .md uniques. Pas de répertoire, pas d'evals, pas de références. Bien pour les skills riches en connaissances et légers en validation.
Checklist
-
skills/<name>/skill.md— instruction avec Purpose, Protocol, Constraints -
skills/<name>/<name>.evals.json— au moins 2 règles de validation - Entrée dans
skills/_registry.json— avec triggers et keywords - Le nom correspond partout — nom du répertoire = nom du skill dans l'eval = nom dans le registry
- Test : envoie un message trigger → vérifie SKILLS_HINT dans les logs
- Test : déclenche intentionnellement un échec d'eval → vérifie que l'avertissement apparaît
Ce qui se passe au runtime
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
Semer des skills dans la DB globale
Les skills en DB (table skills_global) sont la SSOT du Context Router. Le fichier sur disque est la source de vérité pour le contenu ; la DB est l'index rapide pour le matching + l'auto-injection. Ils se synchronisent via des scripts de seeding.
Seeder générique par catégorie
# 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
Fonctionne pour toute catégorie présente dans _registry.json. Prend la première catégorie du tableau comme valeur de colonne DB.
Seeders spécifiques
scripts/seed-startup-skills.ts— codé en dur pour category="startup" (10 skills d'ops de startup)scripts/migrate-skills-to-db.ts— migration en masse historique (tous les fichiers, insert uniquement, pas d'update)
Quand l'exécuter
- Après création d'une nouvelle entrée
.md+_registry.json→ lance le seeder une fois - Après mise à jour du contenu d'un
.mdexistant → le seeder drift-aware met la DB à jour - Bootstrap d'un nouveau projet → les seeders tournent via
vps-sync.shÉtape 1.5 (prévu)
Vérification
sqlite3 data/citadel.db "SELECT name, category, owner_project FROM skills_global ORDER BY id"
owner_project = NULL → global (visible par tous les projets). owner_project = 'my-project' → projet uniquement (ce projet seulement).
Skills projet-uniquement vs globaux
| Type de skill | owner_project |
Cas d'usage |
|---|---|---|
| Global (template) | NULL | Méthodologie générique (TDD, Conventional Commits, AARRR) — utile pour tout projet |
| Projet uniquement | '<project-name>' |
Documents spécifiques à NOTRE codebase (ex. crm-api-reference ne vit que dans arc-v2) |
Déplace un skill existant en projet-uniquement :
sqlite3 data/citadel.db "UPDATE skills_global SET owner_project='my-project' WHERE name='internal-api-docs'"
Le filtre listForProject cadre la visibilité : les autres projets ne verront pas un skill projet-uniquement.