Skip to content

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

text
/etc/ongrid/skills/                  ← one entry in $ONGRID_SKILLS_EXTERNAL_DIRS
└── disk-cleaner/
    ├── skill.json
    └── run.sh                       ← the executable

Chaque 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

json
{
  "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"
}
ChampTypeRequisDescription
namestringouiClé du skill. Doit être en lower_snake correspondant à [a-z0-9_]+. Devient le nom de fonction côté LLM.
descriptionstringouiMontré aux humains (UI) et au LLM (description de fonction).
schemaJSON SchemanonJSON Schema brut pour l'objet args. Manquant = schéma d'objet vide.
entrystringouiChemin 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_allowstring[]nonListe 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_secondsintnonTimeout du subprocess. Zéro retombe sur DefaultSubprocessTimeout (30s).
classenumnonsafe (défaut), mutating, dangerous. Voir taxonomie de classes.
categorystringnonÉ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.

text
$ 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.

ClasseCe qu'elle peut fairePermission de persona requise
safeLecture seule — pas d'effets de bord sur le host ou aucun système.read-only (toute persona)
mutatingCrée / met à jour un état. Réversible.mutating-with-confirm ou dual-sign-required
dangerousIrré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/skills démarre bien).
  • L'entry de chaque manifeste est canonicalisée avec filepath.EvalSymlinks et 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

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

text
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/skills

Faites un tail sur journalctl -u docker-compose@ongrid ou docker compose logs ongrid pour confirmer ce qui a été pris en compte.

Voir aussi

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 :

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