URL: /drover/guides/skills

---
title: Skills
description: SKILL.md files agents load on demand via skill_load.
---

drover implements the [Agent Skills](https://agentskills.io/specification)
specification. A skill is a directory containing a `SKILL.md` file plus
optional `scripts/`, `references/`, and `assets/` subdirectories. The
agent's system prompt advertises name + description; the body loads on
demand via `skill_load`; supporting files are pulled lazily via
`skill_resource`. Progressive disclosure keeps the system prompt small.

## Directory layout

```
my-skill/
├── SKILL.md          # required: metadata + instructions
├── scripts/          # optional: executable code agents can run
├── references/       # optional: extended documentation
└── assets/           # optional: templates, schemas, images
```

## SKILL.md format

```mdx
---
name: pdf-processing
description: Extract text and tables from PDFs, fill forms, merge files. Use when working with PDF documents.
license: Apache-2.0
compatibility: Requires poppler-utils
metadata:
  author: example-org
  version: "1.0"
allowed-tools: Bash(jq:*) Read Edit
---

# pdf-processing

Step-by-step instructions go here. See [references/REFERENCE.md](references/REFERENCE.md)
for the full API.
```

### Frontmatter fields

| field | required | constraints |
| --- | --- | --- |
| `name` | yes | 1-64 chars, `[a-z0-9-]+`, no leading/trailing/consecutive hyphens. Must equal the parent directory name. |
| `description` | yes | 1-1024 chars. Describes what the skill does and when to use it. |
| `license` | no | License name or reference to a bundled file. |
| `compatibility` | no | ≤500 chars. Environment requirements (system packages, network access, etc.). |
| `metadata` | no | Map of string keys to string values for clients to use. |
| `allowed-tools` | no | Space-separated (or list) of pre-approved tools. Experimental. |

Any other frontmatter keys are preserved verbatim under `spec.extra`.

## Build a registry

```ts
import { createSkillRegistry, scanSkillDirs } from "@drover/skills";

const specs = await scanSkillDirs(["./skills", "./node_modules/@my-org/shared-skills"]);
const skills = createSkillRegistry(specs);
```

`scanSkillDirs` walks each root recursively (max depth 3 by default),
finds `SKILL.md` files, dedups by `name` with first-wins. Pass agent-
local dirs ahead of shared library dirs so local skills shadow.

### Strict vs lenient parsing

By default, any spec violation throws and stops the scan. Use
`mode: "lenient"` plus an `onIssue` callback to load best-effort and
surface warnings:

```ts
const specs = await scanSkillDirs([root], {
  mode: "lenient",
  onIssue: (file, issues) => {
    for (const i of issues) console.warn(`${file} — ${i.field}: ${i.message}`);
  },
});
```

## Declare in a spec

```ts
const spec = defineAgent({
  /* ... */
  skills: ["pdf-processing", "factcheck"],
});
```

`spec.skills` is the allowlist. Skills outside it are unreachable for
this agent even if they're in the registry — progressive disclosure
shouldn't bypass least-privilege intent.

## Wire on the run

```ts
runAgent(spec, input, { skills });
```

The harness:

1. Auto-injects `skill_load` and `skill_resource`, both gated by
   `spec.skills`.
2. Appends an "Available skills" section to the system prompt listing
   only allowlisted name + one-line description (plus a `compatibility`
   hint when set).

## Progressive disclosure in practice

1. **Startup (~100 tokens per skill):** name + description in the system
   prompt.
2. **Activation (full body):** the model calls `skill_load(name="<x>")`
   when it decides the skill is relevant.
3. **Resources (on demand):** if the body references `scripts/extract.py`
   or `references/REFERENCE.md`, the model calls
   `skill_resource(name="<x>", resource="<relative-path>")`.

`skill_resource` denies absolute paths and any `..` segments — reads
stay inside the skill directory.

## Inspect a registry

```ts
skills.has("pdf-processing");  // boolean
skills.get("pdf-processing");  // SkillSpec | undefined
skills.list();                  // SkillSpec[]
```

```ts
import { listSkillResources, readSkillResource } from "@drover/skills";

const spec = skills.get("pdf-processing")!;
const res = await listSkillResources(spec);
// { scripts: ["extract.py"], references: ["REFERENCE.md"], assets: [], other: [...] }

const text = await readSkillResource(spec, "references/REFERENCE.md");
```

## Alternative layouts

drover supports the canonical `skills/<name>/SKILL.md` layout out of
the box. For flat layouts (`skills/<name>.md`) or any other on-disk
shape, write a custom loader that produces `SkillSpec[]` and pass to
`createSkillRegistry` — the registry is decoupled from the on-disk
layout.

## Authoring guidance

- Keep the `SKILL.md` body under 500 lines / ~5000 tokens.
- Push detailed reference material to `references/` so the model only
  loads it when explicitly needed.
- Use relative paths from the skill root for file references; keep them
  one level deep.
- Validate with the [skills-ref](https://github.com/agentskills/agentskills/tree/main/skills-ref)
  reference linter before committing.
