Skip to content

Manifiesto de skill

Los skills externos son ejecutables en subprocess descritos por un archivo skill.json colocado bajo uno de los directorios de allow-list del manager. El loader recorre esos directorios en el arranque, parsea cada skill.json y registra un SubprocessSkill en el registry global de skills. El LLM ve entonces el skill junto a las herramientas integradas.

Fuente de verdad: internal/skill/loader.go.

Disposición en disco

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

Cada skill.json está en la raíz de su propio subdirectorio. El árbol de directorios se recorre recursivamente; cualquier archivo llamado skill.json se trata como un manifiesto. Múltiples skills pueden vivir bajo la misma raíz de allow-list.

Esquema del manifiesto

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"
}
CampoTipoObligatorioDescripción
namestringClave del skill. Debe ser lower_snake que coincida con [a-z0-9_]+. Se convierte en el nombre de función que ve el LLM.
descriptionstringSe muestra a humanos (UI) y al LLM (descripción de la función).
schemaJSON SchemanoJSON Schema crudo para el objeto args. Ausente = esquema de objeto vacío.
entrystringRuta al ejecutable. Las rutas relativas se resuelven contra el directorio que contiene skill.json. Las rutas absolutas deben estar bajo una raíz de allow-list.
env_allowstring[]noLista explícita de nombres de variables de entorno reenviadas al hijo. Lista vacía = nada de env (ni siquiera PATH). Añade "PATH" para optar por PATH.
timeout_secondsintnoTimeout del subprocess. Cero recurre a DefaultSubprocessTimeout (30s).
classenumnosafe (por defecto), mutating, dangerous. Ver taxonomía de clases.
categorystringnoEtiqueta de grupo de forma libre. Por defecto external. La UI agrupa los skills de subprocess por esto.

Protocolo wire

El subprocess es invocado con stdin = objeto JSON de args, stdout = objeto JSON de resultado, stderr = líneas de log para el manager.

text
$ cat /tmp/args.json
{"path": "/var/cache", "dry_run": true}

$ run.sh < /tmp/args.json
{"freed_bytes": 1048576, "files_deleted": 17}

Un código de salida distinto de cero se trata como fallo. Stderr se captura en la línea de tiempo de eventos de tool-call para que el LLM pueda leer el progreso parcial.

El objeto de resultado se devuelve textualmente al LLM. El kernel del agente lo formatea como la respuesta de la llamada de herramienta; se espera que el LLM razone sobre la forma del JSON.

Taxonomía de clases

La misma taxonomía {safe, mutating, dangerous} aplica a los skills nativos y a los skills de subprocess.

ClaseQué puede hacerPermiso de persona requerido
safeSolo lectura — sin efectos secundarios en el host ni en sistema alguno.read-only (cualquier persona)
mutatingCrea / actualiza estado. Reversible.mutating-with-confirm o dual-sign-required
dangerousIrreversible (deletes, restarts, exec-arbitrary).dual-sign-required (SOP)

El campo permission_mode de la persona filtra qué clases pueden ejecutarse sin confirmación. Ver Formato de persona de agente.

Reglas de allow-list

Los operadores configuran los directorios de allow-list vía ONGRID_SKILLS_EXTERNAL_DIRS (rutas absolutas separadas por dos puntos o por comas). El loader las aplica estrictamente:

  • Cada directorio debe ser una ruta absoluta. Las rutas relativas se omiten con una línea de log.
  • Las rutas inexistentes se omiten (de modo que una instalación fresca sin /etc/ongrid/skills arranca bien).
  • El entry de cada manifiesto se canoniza con filepath.EvalSymlinks y se verifica que viva bajo la raíz de allow-list. Un symlink que apunta fuera de la raíz es rechazado (entry %s escapes allowlist root %s).

El sandboxing más allá de eso es responsabilidad del subprocess. Si el skill necesita estar fuertemente contenido, ejecútalo bajo un wrapper (bwrap, firejail, nsenter) referenciado como el entry.

Comportamiento del 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)
  • Los fallos de validación por manifiesto se loguean y omiten. Un pack roto no debería bloquear el arranque.
  • Los nombres duplicados se omiten en lugar de generar error (de modo que un redeploy que añade un nuevo manifiesto antes de remover el viejo no crashea al manager).
  • El loader devuelve el conteo de skills registrados exitosamente. El arranque del manager no se bloquea por el loader de skills: un dir externo vacío es un no-op.

Logging en el arranque

El manager loguea una línea por manifiesto:

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

Haz tail a journalctl -u docker-compose@ongrid o docker compose logs ongrid para confirmar qué fue recogido.

Véase también

Metadatos de skill nativo (frontmatter de SKILL.md)

Los skills integrados que se entregan bajo ./skills/ usan un formato SKILL.md con frontmatter YAML más rico que interopera con los ecosistemas de skills de openclaw / claude-code. El esquema se define en 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 ...

Para skills de subprocess escritos por terceros, prefiere el formato skill.json más simple de arriba. SKILL.md es para skills que se compilan dentro del binario del manager.