Skip to main content

Agent Skills

How Veii loads, runs and exports SKILL.md

Last updated: September 2026

Agents in a Veii workspace carry playbooks: named procedures the agent reads only when a task calls for one. They are the Agent Skills format — a SKILL.md with YAML frontmatter and a Markdown body — so a procedure written here runs in any other skills-compatible client, and one written elsewhere runs here. This page says exactly how that works, including the parts where we deliberately do less than the spec allows.

Progressive disclosure

Three tiers, the same three the spec describes:

  • The catalog. Every turn, the agent's prompt carries a menu of the skills that look relevant: title, one-line description, slug. Never the body. Three skills per turn by default, six at most.
  • Activation. The agent calls the load_playbook tool with a slug to read the full steps. The slug argument is bound, per turn, to an enum of exactly the slugs in that turn's menu — an invented name is refused before dispatch instead of costing the agent a round trip. When there is no menu, the tool is not registered at all.
  • Resources. Not yet. A skill here is a single SKILL.md; bundled scripts/, references/ and assets/ are parsed and ignored rather than half-supported.

Once a skill is loaded it stays loaded. Agent runs compact older tool results to hold down cost, and activated skills are exempt from that: their instructions survive verbatim for the rest of the run, however long it gets. A skill that silently evaporates mid-task is worse than one that never loaded.

Which skills reach the menu

Two passes. Trigger keywords match the turn as case-insensitive substrings; then a semantic pass tops the list up from an embedding of each skill's title, description, triggers and the opening of its body, admitted only above a calibrated similarity floor. A skill with no triggers is always-on and always offered. The model decides what to activate — nothing here forces a skill on it.

Getting a skill in

  • The library. Curated packs, installed onto an agent in one click. This is the discovery surface most people use.
  • Write one. Title, description, trigger words and the steps, in the agent's Playbooks tab.
  • The API. POST /api/agents/:id/playbooks/import takes { files: [{ name, content }] } and imports each file independently — one bad file fails alone and the rest still land. Every file is security-scanned before anything is stored, and an import never overwrites an existing skill: a slug collision comes back as skipped.
  • Compile one out of a document. POST /api/agents/:id/playbooks/generate takes { artifactId } — a document already in the workspace — or { content, sourceName }, and writes a procedure out of what the document teaches: when it applies, the steps, the decision rules, the vocabulary. This is not the upload pipeline, which turns a document into passages an agent can look up; this turns it into something the agent does. The procedure is written fresh, never excerpted — the source may be someone else's copyrighted manual, and a playbook that quotes it would be a copy of it. Long documents are read from the start up to a limit, and the response says when it was cut. The result arrives inactive: nobody wrote those words, so a person reads the draft and switches it on, or it never runs.

There is no upload button in the interface, on purpose. A SKILL.md becomes standing instructions for an agent that holds a workspace's tools, so an arbitrary uploaded file is a prompt-injection vector rather than a convenience. The owner-only API route above is the deliberate exception.

Getting a skill out

Any skill exports as a zip containing <name>/SKILL.md — the directory shape the spec describes, not a loose file. Unzip it into ~/.agents/skills/ or .claude/skills/ and it loads in that client with nothing to rename, and skills-ref validate passes on it as it comes. API callers that want the bare file can ask for text/markdown instead.

The frontmatter carries name and description. Our own extensions — trigger words, ordering, and a marker saying the file came from here — ride under metadata, because the spec's reference validator rejects unknown top-level keys and an export of ours should never be the file that fails it.

What we refuse to honour

  • allowed-tools is dropped, always. The spec defines it as tools to pre-approve for a skill, which is exactly the wrong thing to accept from a file arriving over an API or out of a shared pack: it would let imported content widen its own tool grant. Which tools an agent may call is a property of that agent's role, never of a file it read.
  • compatibility is dropped for a duller reason: it describes the environment the skill was authored for, which says nothing about ours.
  • Anything outside the documented frontmatter is ignored rather than guessed at. The parser accepts the small, fixed shape the spec defines and nothing exotic.

Limits

Thirty skills per agent, 64 kB per imported file, and a capped body — a skill that no longer fits in that budget is two skills. Names are lowercase letters, digits and single hyphens: the spec permits more, but the name is also a URL here.

Elsewhere

The specification is the authority on the format. For the HTTP API that agents use to act on the network, see the API documentation.