Manifeste de skill
Les skills externes sont des exécutables subprocess décrits par un fichier skill.json déposé sous l'un des répertoires d'allow-list du manager. Le loader parcourt ces répertoires au boot, parse chaque skill.json, et enregistre un SubprocessSkill dans le registre global de skills. Le LLM voit alors le skill aux côtés des outils intégrés.
Source de vérité : internal/skill/loader.go.
Disposition sur disque
/etc/ongrid/skills/ ← one entry in $ONGRID_SKILLS_EXTERNAL_DIRS
└── disk-cleaner/
├── skill.json
└── run.sh ← the executableChaque skill.json est en haut de son propre sous-répertoire. L'arborescence est parcourue récursivement ; tout fichier nommé skill.json est traité comme un manifeste. Plusieurs skills peuvent vivre sous la même racine d'allow-list.
Schéma du manifeste
{
"name": "disk_cleaner",
"description": "Free up disk by clearing stale build caches and journals.",
"schema": {
"type": "object",
"properties": {
"path": { "type": "string", "description": "Root path to clean." },
"dry_run": { "type": "boolean", "default": true }
},
"required": ["path"]
},
"entry": "run.sh",
"env_allow": ["PATH", "HOME"],
"timeout_seconds": 60,
"class": "mutating",
"category": "ops"
}| Champ | Type | Requis | Description |
|---|---|---|---|
name | string | oui | Clé du skill. Doit être en lower_snake correspondant à [a-z0-9_]+. Devient le nom de fonction côté LLM. |
description | string | oui | Montré aux humains (UI) et au LLM (description de fonction). |
schema | JSON Schema | non | JSON Schema brut pour l'objet args. Manquant = schéma d'objet vide. |
entry | string | oui | Chemin vers l'exécutable. Les chemins relatifs se résolvent par rapport au répertoire contenant skill.json. Les chemins absolus doivent se trouver sous une racine d'allow-list. |
env_allow | string[] | non | Liste explicite des noms de variables d'env transmises au child. Liste vide = aucun env du tout (pas même PATH). Ajoutez "PATH" pour opt-in à PATH. |
timeout_seconds | int | non | Timeout du subprocess. Zéro retombe sur DefaultSubprocessTimeout (30s). |
class | enum | non | safe (défaut), mutating, dangerous. Voir taxonomie de classes. |
category | string | non | Étiquette de groupe en forme libre. Défaut external. L'UI groupe les skills subprocess par ceci. |
Protocole wire
Le subprocess est invoqué avec stdin = objet args JSON, stdout = objet résultat JSON, stderr = lignes de log pour le manager.
$ cat /tmp/args.json
{"path": "/var/cache", "dry_run": true}
$ run.sh < /tmp/args.json
{"freed_bytes": 1048576, "files_deleted": 17}Un code de sortie non nul est traité comme un échec. Stderr est capturé dans la timeline d'événements d'appel d'outil pour que le LLM puisse lire la progression partielle.
L'objet résultat est retourné verbatim au LLM. Le kernel d'agent le formate comme la réponse de l'appel d'outil ; le LLM est censé raisonner sur la forme JSON.
Taxonomie de classes
La même taxonomie {safe, mutating, dangerous} s'applique aux skills natifs et aux skills subprocess.
| Classe | Ce qu'elle peut faire | Permission de persona requise |
|---|---|---|
safe | Lecture seule — pas d'effets de bord sur le host ou aucun système. | read-only (toute persona) |
mutating | Crée / met à jour un état. Réversible. | mutating-with-confirm ou dual-sign-required |
dangerous | Irréversible (supprime, redémarre, exec-arbitrary). | dual-sign-required (SOP) |
Le champ permission_mode de la persona gate quelles classes peuvent s'exécuter sans confirmation. Voir Format de persona d'agent.
Règles d'allow-list
Les opérateurs configurent les répertoires d'allow-list via ONGRID_SKILLS_EXTERNAL_DIRS (chemins absolus séparés par deux-points ou virgules). Le loader les applique strictement :
- Chaque répertoire doit être un chemin absolu. Les chemins relatifs sont sautés avec une ligne de log.
- Les chemins inexistants sont sautés (donc une install fraîche sans
/etc/ongrid/skillsdémarre bien). - L'
entryde chaque manifeste est canonicalisée avecfilepath.EvalSymlinkset vérifiée comme vivant sous la racine d'allow-list. Un symlink qui pointe en dehors de la racine est rejeté (entry %s escapes allowlist root %s).
Le sandboxing au-delà de ça est de la responsabilité du subprocess. Si le skill doit être étroitement contenu, exécutez-le sous un wrapper (bwrap, firejail, nsenter) référencé comme l'entry.
Comportement du loader
LoadDirs(cfg)
for each dir in cfg.Dirs:
filepath.Walk(dir)
for each skill.json found:
parseManifest(path)
buildSubprocessSkill(manifest, path, root)
if skill already registered: skip (log line)
else Register(skill)- Les échecs de validation par manifeste sont loggués et sautés. Un pack cassé ne devrait pas bloquer le boot.
- Les noms en double sont sautés plutôt que de produire une erreur (pour qu'un redéploiement qui dépose un nouveau manifeste avant de retirer l'ancien ne fasse pas crasher le manager).
- Le loader retourne le compte de skills enregistrés avec succès. Le démarrage du manager est non-bloquant sur le loader de skills : un répertoire externe vide est un no-op.
Logging au démarrage
Le manager logge une ligne par manifeste :
skill loader: registered subprocess skill "disk_cleaner" from /etc/ongrid/skills/disk-cleaner/skill.json
skill loader: skill "broken_one" already registered, skipping /etc/ongrid/skills/broken-one/skill.json
skill loader: parse /etc/ongrid/skills/typo/skill.json: invalid character ',' looking for beginning of object key
skill loader: build "bad_path": entry /tmp/escape.sh escapes allowlist root /etc/ongrid/skillsFaites un tail sur journalctl -u docker-compose@ongrid ou docker compose logs ongrid pour confirmer ce qui a été pris en compte.
Voir aussi
- Capacités → Skills — catalogue de skills intégrés.
- Format de persona d'agent — comment une persona choisit quels skills elle peut appeler.
- Marketplace — installer un pack de skills comme une unité.
- REST API →
/v1/skills— listing et exécution directe.
Métadonnées de skill natif (frontmatter SKILL.md)
Les skills intégrés livrés sous ./skills/ utilisent un format SKILL.md plus riche en YAML-frontmatter qui interopère avec les écosystèmes de skills openclaw / claude-code. Le schéma est défini dans internal/manager/biz/aiops/chatruntime/types.go :
---
name: query_promql
description: Run a PromQL query and return the result matrix.
when_to_use: When the user asks for current or recent metric values.
activation:
mode: always
metadata:
os: [linux, darwin]
requires:
bins: []
config: []
ongrid:
scope: manager
activation:
mode: always
tools:
- name: query_promql
impl: builtin:prom.QueryPromQL
class: read
description: Execute a PromQL query and return the matrix.
---
# query_promql
PromQL query tool ...Pour les skills subprocess écrits par des tiers, préférez le format plus simple skill.json ci-dessus. SKILL.md est pour les skills qui compilent dans le binaire du manager.