The 4-layer skill format

ExplanationUpdated 6 min read
View as Markdown
On this page

A complete skill ships two things in one signed package:

  • The 4-layer format: content folders an agent reads and drills into.

  • The guidance block in client/schema.yaml: metadata the platform reads to decorate every reply with _guidance, telemetry_signal and, on request, _findings.

Ship only one and the skill is half-built. For the craft of making each layer hold up, read Write skills that hold up.

Folder layout

skills/<your-skill>/
├── SKILL.md                 ← Layer 1: the router (required)
├── client/
│   └── schema.yaml          ← API surface + guidance block
├── references/              ← Layer 2: procedures (recommended)
│   └── <task-name>.md
├── learnings/               ← Layer 3: lessons with provenance (recommended)
│   └── <yyyy-mm-dd-slug>/
│       ├── metadata.json
│       └── artifacts/what-we-learned.md
├── registry/                ← Layer 4: typed assets agents install (recommended)
│   ├── registry.json
│   └── <item-name>/
│       ├── registry-item.json
│       └── <asset files>
└── scripts/                 ← optional: checks the agent runs on its own work
    └── verify-<thing>.mjs

Layer 1: SKILL.md, the router

At most 500 lines, with frontmatter. The body is a decision tree that points at references/ files, not a manual. The description: line is the trigger: list every verb and noun an agent might meet, then name the sibling skills to use instead.

Put in it: frontmatter (name, description, version, and optionally category, triggers, requires_auth, vendor, entitlements); at most one <HARD-GATE> block for the single riskiest mistake; a table "if the user wants X → read references/X.md"; a short list of anti-patterns; and pointers to learnings/, registry/ and scripts/.

Layer 2: references/, procedures

One Markdown file per task or per trap, 50 to 200 lines each. Two shapes:

  • WRONG / RIGHT to teach a trap: the broken version, then the fix, with real values.

  • Steps / Gotchas / Verify to teach a multi-step job.

Every MUST is followed by why, so the agent can judge edge cases. Agents on OPVS read these with skill_read_reference; agents on other tools read the files after install.

Layer 3: learnings/, what you learned

One folder per lesson:

  • metadata.json: title, summary, created_at, updated_at, references[] (provenance: the issue, incident or change that produced it), and optionally tags[] and stale_after.

  • artifacts/what-we-learned.md: the lesson itself, plus any supporting files.

Agents read every summary and open the artifact only when it matches the task, so the summary is the trigger. Provenance in references[] is required for published learnings. Tell agents in SKILL.md that learnings are starting points to check, not ground truth.

Layer 4: registry/, assets agents install

Things the agent installs instead of writing: board templates, document starters, prompt packs, HTML components. Each item has its own folder with a registry-item.json and its files.

Required fields in registry-item.json: $schema, name, type, title, description, version, vendor, skill, files. Add preview for items with a visible surface, and references[] provenance for published items. type is one of opvs:block (drop-in), opvs:component (parameterised), opvs:template (multi-file starting point) or opvs:blueprint (multi-skill workspace setup).

Each item has its own semver, independent of the skill, and belongs to exactly one skill (the skill field).

scripts/, optional

Deterministic checks the agent runs on its own work and pastes the output of. Name each one in SKILL.md so the agent knows when to run it.

The guidance block

Add it to client/schema.yaml, next to your methods.

guidance:                       # skill level
  use: "what this skill is for, one line"
  not:
    - "<sibling-skill> → what to do instead"
  intent_aliases:               # every name a free-text input goes by
    - "query"
    - "search"
  pitfalls:
    - "<the top gotcha, one sentence>"

methods:
  getThing:
    description: Plain-English summary.
    guidance:                   # method level
      use: "when an agent should call this"
      next: "updateThing, listThings"
      warn: "the one thing that catches first-time callers"
      telemetry_signal_default: "warm"
    http: GET /things/{id}
    params:
      id: { type: uuid, required: true, description: The thing's id. }
    response:
      format: yaml

Three rules apply to every vendor:

Rule

What it means for you

Declare intent_aliases

If any method takes a free-text search input, list every name it goes by under guidance.intent_aliases. The platform never guesses. A package with no aliases gets a review warning, because agents cannot find it by the words they use.

_findings comes from the platform

When a caller sends X-OPVS-Audit-Level: all, the platform adds _findings (default [{audit: "ok"}]). Set audit_findings_template only if your skill has real audit results.

telemetry_signal_default defaults to absent

Set cold, warm or hot only where the method has natural usage meaning. The generator warns when it is missing.

Nested object and array parameters

Declare the full shape inline; every generator then emits the nested JSON Schema and agents see the sub-fields.

params:
  workflow:
    type: object
    required: true
    description: The workflow to run.
    properties:
      smartlead:
        type: object
        properties:
          connection_id:
            type: string
            required: true          # per-field required, not a sibling list
            description: Smartlead account connection id.
  admin_regions:
    type: array
    items:
      type: object
      properties:
        country: { type: string, required: true, description: ISO country code. }
        cities:  { type: array, items: string }
  • Each sub-field carries its own required. There is no sibling required: [names] list.

  • items is a type name (items: string) or a full object spec.

  • Validation reaches every level and reports a dotted path. Nesting is capped at 12 levels.

  • oneOf, allOf, anyOf and $ref pass through but are not validated.

  • A schema never restricts what callers send: undeclared keys still reach your API; a mismatch only produces a warning.

What happens at runtime

  • The envelope is added by the platform. It reads your guidance block and decorates each reply. You write no code for it.

  • The layer files travel with the install. Agents open references/, learnings/ and registry/ files directly, with no API call.

Packaging the layers

Nothing extra is needed in package.yaml: the publish command packs the whole package folder (minus a fixed exclude list), so new folders are included and signed automatically. See The package manifest.

  • Adding the layers to an existing skill is a minor version bump.

  • Bump a registry item's own version when you change a file inside it.

Questions

Do I need all four layers? No. Only SKILL.md is required. Ship at least one references/ file so the agent has somewhere to drill into.

Can I publish without the guidance block? Yes, but agents lose the per-method next and warn hints. Ship it.

Is a learnings folder the same as LEARNINGS.md? No. The security review looks for root files (README.md, SKILL.md, CHANGELOG.md). learnings/ inside a skill is the structured lesson format.

My skill teaches a method rather than calling an API. What then? Publish it guidance-only: no methods: in schema.yaml, rich references/. Never declare a method you do not serve, or every call to it fails.

Next

Write skills that hold up.

Did this answer your question?