Skip to content

Skill manifest

External skills are subprocess executables described by a skill.json file dropped under one of the manager's allow-list directories. The loader walks those directories at boot, parses each skill.json, and registers a SubprocessSkill in the global skill registry. The LLM then sees the skill alongside built-in tools.

Source of truth: internal/skill/loader.go.

Layout on disk

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

Each skill.json is at the top of its own subdirectory. The directory tree is walked recursively; any file named skill.json is treated as a manifest. Multiple skills can live under the same allow-list root.

Manifest schema

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"
}
FieldTypeRequiredDescription
namestringyesSkill key. Must be lower_snake matching [a-z0-9_]+. Becomes the LLM-facing function name.
descriptionstringyesShown to humans (UI) and to the LLM (function description).
schemaJSON SchemanoRaw JSON Schema for the args object. Missing = empty object schema.
entrystringyesPath to the executable. Relative paths resolve against the directory holding skill.json. Absolute paths must lie under an allow-list root.
env_allowstring[]noExplicit list of env-var names forwarded to the child. Empty list = no env at all (not even PATH). Add "PATH" to opt in to PATH.
timeout_secondsintnoSubprocess timeout. Zero falls back to DefaultSubprocessTimeout (30s).
classenumnosafe (default), mutating, dangerous. See class taxonomy.
categorystringnoFree-form group label. Defaults to external. UI groups subprocess skills by this.

Wire protocol

The subprocess is invoked with stdin = JSON args object, stdout = JSON result object, stderr = log lines for the manager.

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

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

Non-zero exit code is treated as failure. Stderr is captured into the tool-call event timeline so the LLM can read partial progress.

The result object is returned verbatim to the LLM. The agent kernel formats it as the tool call's response; the LLM is expected to reason over the JSON shape.

Class taxonomy

The same {safe, mutating, dangerous} taxonomy applies to native skills and subprocess skills.

ClassWhat it can doPersona permission required
safeRead-only — no side effects on the host or any system.read-only (any persona)
mutatingCreates / updates state. Reversible.mutating-with-confirm or dual-sign-required
dangerousIrreversible (deletes, restarts, exec-arbitrary).dual-sign-required (SOP)

The persona's permission_mode field gates which classes can run without confirmation. See Agent persona format.

Allow-list rules

Operators configure allow-list directories via ONGRID_SKILLS_EXTERNAL_DIRS (colon- or comma-separated absolute paths). The loader enforces them strictly:

  • Each directory must be an absolute path. Relative paths are skipped with a log line.
  • Non-existent paths are skipped (so a fresh install with no /etc/ongrid/skills boots fine).
  • Each manifest's entry is canonicalised with filepath.EvalSymlinks and checked to live under the allow-list root. A symlink that points outside the root is rejected (entry %s escapes allowlist root %s).

Sandboxing beyond that is the subprocess's responsibility. If the skill needs to be tightly contained, run it under a wrapper (bwrap, firejail, nsenter) referenced as the entry.

Loader behavior

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)
  • Per-manifest validation failures are logged and skipped. One broken pack should not block boot.
  • Duplicate names are skipped rather than erroring (so a redeploy that drops a new manifest before removing the old one doesn't crash the manager).
  • Loader returns the count of successfully registered skills. Manager startup is non-blocking on the skill loader: an empty external dir is a no-op.

Logging at startup

The manager logs one line per manifest:

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

Tail journalctl -u docker-compose@ongrid or docker compose logs ongrid to confirm what was picked up.

See also

Native skill metadata (SKILL.md frontmatter)

Built-in skills shipped under ./skills/ use a richer YAML-frontmatter SKILL.md format that interoperates with the openclaw / claude-code skill ecosystems. The schema is defined in 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 ...

For subprocess skills written by third parties, prefer the simpler skill.json format above. SKILL.md is for skills that compile into the manager binary.